package com.lancoo.ccas53.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lancoo.ccas53.arrangecourse.ArrangeCourseDataSource;
import com.lancoo.ccas53.arrangecourse.ArrangeCourseService;
import com.lancoo.ccas53.arrangecourse.common.BinaryUtil;
import com.lancoo.ccas53.arrangecourse.common.ClassHourUtil;
import com.lancoo.ccas53.arrangecourse.dataprocess.ClassHourScheduleConvert;
import com.lancoo.ccas53.arrangecourse.dataprocess.GenerateSchedulingData;
import com.lancoo.ccas53.arrangecourse.dataprocess.GenerateTimeslotRoom;
import com.lancoo.ccas53.arrangecourse.entities.ClassHour;
import com.lancoo.ccas53.arrangecourse.entities.ClassTimeCodeContext;
import com.lancoo.ccas53.arrangecourse.entities.TeachingClassUnit;
import com.lancoo.ccas53.arrangecourse.entities.TimeslotRoom;
import com.lancoo.ccas53.entity.*;
import com.lancoo.ccas53.exception.BizException;
import com.lancoo.ccas53.mapper.*;
import com.lancoo.ccas53.pojo.common.*;
import com.lancoo.ccas53.pojo.constant.GlobalConstant;
import com.lancoo.ccas53.pojo.constant.ScheduleState;
import com.lancoo.ccas53.pojo.dto.*;
import com.lancoo.ccas53.pojo.excel.ExcelClassVo;
import com.lancoo.ccas53.pojo.excel.ExcelSegment;
import com.lancoo.ccas53.pojo.excel.ExcelTimeType;
import com.lancoo.ccas53.pojo.excel.ExportTimeslotRoom;
import com.lancoo.ccas53.pojo.vo.*;
import com.lancoo.ccas53.service.*;
import com.lancoo.ccas53.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 * 课表 服务实现类
 * </p>
 *
 * @author quin.song
 * @since 2024-05-20
 */
@Slf4j
@Service
public class ScheduleServiceImpl extends ServiceImpl<ScheduleMapper, Schedule> implements ScheduleService {


    @Resource
    private RedissonClient redissonClient;

    @Resource
    private TeachingClassMapper teachingClassMapper;


    @Resource
    private TeacherService teacherService;
    @Resource
    private RoomMapper roomMapper;
    @Resource
    private BasicRuleService basicRuleService;
    @Resource
    private RuleTimeProhibitMapper ruleTimeProhibitMapper;
    @Resource
    private RuleTimeProhibitService ruleTimeProhibitService;
    @Resource
    private TaskInfoService taskInfoService;
    @Resource
    private ScheduleMapper scheduleMapper;
    @Resource
    private ScheduleConflictInfoMapper scheduleConflictInfoMapper;
    @Resource
    private TeachingClassService teachingClassService;
    @Resource
    private RuleUsableService ruleUsableService;
    @Resource
    private TeachingClassWeekService teachingClassWeekService;
    @Resource
    private SubClassGroupService subClassGroupService;
    @Resource
    private CourseService courseService;
    @Resource
    private TeachingClassTeacherService teachingClassTeacherService;


    @Resource
    private SubClassService subClassService;
    @Resource
    private ScheduleConflictInfoService scheduleConflictInfoService;
    @Resource
    private StudentService studentService;

    @Resource
    private RuleWeekDayService ruleWeekDayService;
    @Resource
    private TeachingClassStudentMapper teachingClassStudentMapper;
    @Resource
    private ArrangeCourseDataSource arrangeCourseDataSource;
    @Resource
    private RedisUtil redisUtil;

    @Resource
    private TeachingClassStudentService teachingClassStudentService;


    @Resource
    private ScheduleSelectService scheduleSelectService;

    @Resource
    private ScheduleService scheduleService;

    @Resource
    private RoomService roomService;


    @Resource
    private ArrangeCourseService arrangeCourseService;
    @Resource
    private MajorGradeMapper majorGradeMapper;


    @Override
    public List<ArrangeTeachingClassDto> getTeachingClassDate(Integer taskId, String campusId, String collegeId, Integer majorProp) {
        //获取课程教学班
        List<ArrangeTeachingClassDto> allTeachingClass = teachingClassMapper.getCourseArrangeTeachingClassDto(taskId, campusId, collegeId, majorProp, null);
        //公共课教学班院系id置为空字符串
//        allTeachingClass.stream()
//                .filter(teachingClass -> teachingClass.getMajorProp() == 1)
//                .forEach(teachingClass -> teachingClass.setCourseCollegeId(""));
        allTeachingClass.forEach(o -> {
            if (o.getRoomType() == null) {
                o.setRoomType(-111);
            }
        });
        //补充教师信息
        List<Long> teachingClassIds = allTeachingClass.stream().map(ArrangeTeachingClassDto::getTeachingClassId).collect(Collectors.toList());
        Map<String, List<Teacher>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIdsArrange(teachingClassIds)
                .stream().collect(Collectors.groupingBy(teacher -> teacher.getTeachingClassId() + "-" + teacher.getHourType()));
        allTeachingClass.forEach(o -> {
            //补充教师信息 单独添加，因为教师业务以后可能会变化
            List<Teacher> teachers = teachingClassToTeacher.get(o.getTeachingClassId() + "-" + o.getHourType());
            if (CollUtil.isNotEmpty(teachers)) {
                String teacherIds = StrUtil.join(",", teachers.stream().map(Teacher::getTeacherId).collect(Collectors.toList()));
                String teacherNames = StrUtil.join(",", teachers.stream().map(Teacher::getTeacherName).collect(Collectors.toList()));
                o.setTeacherIds(teacherIds);
                o.setTeacherNames(teacherNames);
            }
        });
        return allTeachingClass;
    }


    //    @Override
    public void teacherScheduleToExcel0(HttpServletResponse response, Integer taskId, Long teacherId, String baseCollegeName) {

        TaskInfo taskInfo = taskInfoService.getById(taskId);

        Teacher teacher = teacherService.getById(teacherId);
        String fileName = teacher.getTeacherName() + "(" + teacher.getTeacherId() + ")" + "课表.xlsx";
        String storePath = taskInfo.getSchoolName() + File.separator + fileName;
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;


        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);

        writer.getStyleSet().setWrapText();

        List<TeachingClassWeekScheduleDto> resultList = scheduleService.getTeacherSchedule(taskId, teacherId, null);
        //根据最大周次生成课表模板
        int periods = basicRuleService.getMaxPeriod(taskId);
        String title = "{} 教师课表  \n  {}";
        writer.merge(taskInfo.getCycleDay(), StrUtil.format(title, teacher.getTeacherName(), taskInfo.getTermName()), false);
        writer.setRowHeight(0, 40);
        long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();
        long sectionNum = resultList.stream()
                .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
                .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
        String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
        String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
        writer.merge(taskInfo.getCycleDay(), filter, false);
        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}({}) \n{}\n{}{}\n{}";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String buildingName = byWeekList.get(0).getBuildingName();
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String format = StrUtil.format(scheduleHour, item.getCourseName(), GlobalConstant.hourTypeMap.get(hourType)
                                , item.getTeachingClassName(), buildingName, roomName, weekString);

                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                        if ("--".equals(s)) {
                            s = "";
                        } else {
                            s += "\n";
                        }
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                    });
                });
            });
        }

        writer.write(rows, false);
        setExcelForm(writer, rows, 2);

        if (null != response) {
            // 下边两行任取一行都可以
            response.addHeader("Content-Type", "application/vnd.ms-excel;charset=UTF-8");
            // response.addHeader("Content-Type", "application/octet-stream");
            response.addHeader("Content-Disposition", writer.getDisposition("教师导出.xls", StandardCharsets.UTF_8));
        }
        try {
            writer.flush(response.getOutputStream(), true);
        } catch (IOException e) {
            log.error("场地导出错误" + e);
        }
        writer.close();
    }

    @Override
    public void teacherScheduleToExcel(HttpServletResponse response, Integer taskId, Long teacherId, String baseCollegeName) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);

        Teacher teacher = teacherService.getById(teacherId);
        String fileName = teacher.getTeacherName() + "(" + teacher.getTeacherId() + ")" + "课表.xlsx";
        String storePath = taskInfo.getSchoolName() + File.separator + fileName;
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;


        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);

        writer.getStyleSet().setWrapText();

        List<TeachingClassWeekScheduleDto> resultList = scheduleService.getTeacherSchedule(taskId, teacherId, null);
        //根据最大周次生成课表模板
        int periods = basicRuleService.getMaxPeriod(taskId);
        String title = "{}教师课表";

        CellStyle header = writer.createCellStyle();
        Font headerFont = writer.createFont();
        headerFont.setFontHeightInPoints((short) 15);
        header.setFont(headerFont);
        header.setAlignment(HorizontalAlignment.CENTER);
        header.setBorderBottom(BorderStyle.THIN);
        header.setBorderLeft(BorderStyle.THIN);
        header.setBorderRight(BorderStyle.THIN);
        header.setBorderTop(BorderStyle.THIN);

        writer.merge(0, 0, 0, taskInfo.getCycleDay(), StrUtil.format(title, taskInfo.getTermName()), header);
        writer.passCurrentRow();

        writer.setRowHeight(0, 40);

        String filterTem = "教师姓名: {}    教师职称: {} ";
        String filter = StrUtil.format(filterTem, teacher.getTeacherName() + "(" + teacher.getTeacherId() + ")", teacher.getProfessionalTitle());
        writer.merge(1, 1, 0, taskInfo.getCycleDay(), filter, header);
        writer.passCurrentRow();

        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}\n{}{}\n{}\n";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String buildingName = byWeekList.get(0).getBuildingName();
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String format = StrUtil.format(scheduleHour,
                                item.getTeachingClassName(), buildingName, roomName, weekString);

                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                        if ("--".equals(s)) {
                            s = "";
                        } else {
                            s += "\n";
                        }
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                    });
                });
            });
        }

        writer.write(rows, false);

        String time = "导出时间: {} ";
        writer.merge(taskInfo.getCycleDay(), StrUtil.format(time, DateUtil.now()), false);

        setExcelForm(writer, rows, 2);


        if (null != response) {
            // 下边两行任取一行都可以
            response.addHeader("Content-Type", "application/vnd.ms-excel;charset=UTF-8");
            // response.addHeader("Content-Type", "application/octet-stream");
            response.addHeader("Content-Disposition", writer.getDisposition("教师导出.xls", StandardCharsets.UTF_8));
        }
        try {
            writer.flush(response.getOutputStream(), true);
        } catch (IOException e) {
            log.error("场地导出错误" + e);
        }
        writer.close();
    }


    @Override
    public List<ArrangeRoomDto> getArrangeRoom(Integer taskId, String schoolId, String term, String campusId) {
        List<ArrangeRoomDto> arrangeRoom = roomMapper.getArrangeRoom(taskId, schoolId, term, campusId);
        return arrangeRoom;
    }

    @Override
    public List<ArrangePeriod> getArrangeTimeCode(Integer taskId, String schoolId, String term, String collegeId) {
        List<ArrangePeriod> periodCode = new ArrayList<>();
        List<RuleWeekDay> weekDays = basicRuleService.getWeekDays(taskId);
        //禁排
        Set<String> timeProhibit = basicRuleService.getTimeProhibit(taskId, collegeId)
                .stream().map(RuleTimeProhibit::getTimeCode).collect(Collectors.toSet());

        Map<Integer, List<RuleWeekDay>> campusWeekDays = weekDays.stream().collect(Collectors.groupingBy(RuleWeekDay::getCampusId));
        for (Map.Entry<Integer, List<RuleWeekDay>> integerListEntry : campusWeekDays.entrySet()) {
            Integer campusId = integerListEntry.getKey();
            integerListEntry.getValue().forEach(weekDay -> {
                weekDay.getPeriodSchemes().forEach(periodScheme -> {
                    Integer dayNo = Integer.parseInt(weekDay.getWeekDayCode());
                    //第几节
                    Integer period = periodScheme.getPeriod();
                    //学时code
                    String code = weekDay.getWeekDayCode() + String.format("%02d", period);
                    //是否属于禁排
                    Integer isProhibit = timeProhibit.contains(code) ? 1 : 0;
                    //名字格式修改
                    String name = "周" + weekDay.getWeekDayCode() + "第" + period + "节";
                    periodCode.add(ArrangePeriod.builder().campusId(campusId).timeCode(code).codeName(name).dayNo(dayNo).periodType(periodScheme.getPeriodType()).period(period).isProhibit(isProhibit).build());

                });

            });
        }
        ClassTimeCodeContext.setTimeCodeList(periodCode.stream().filter(o -> o.getIsProhibit() == 0).collect(Collectors.toList()));
        return periodCode;
    }

    @Override
    public List<ArrangePeriod> getArrangeTimeCodeV2(Integer taskId, String schoolId, String term, String collegeId) {
        List<ArrangePeriod> periodCode = new ArrayList<>();
        List<RuleWeekDay> weekDays = basicRuleService.getWeekDays(taskId);
        //禁排
        Set<String> timeProhibit = new HashSet<>();

        Map<Integer, List<RuleWeekDay>> campusWeekDays = weekDays.stream().collect(Collectors.groupingBy(RuleWeekDay::getCampusId));
        for (Map.Entry<Integer, List<RuleWeekDay>> integerListEntry : campusWeekDays.entrySet()) {
            Integer campusId = integerListEntry.getKey();
            integerListEntry.getValue().forEach(weekDay -> {
                weekDay.getPeriodSchemes().forEach(periodScheme -> {
                    Integer dayNo = Integer.parseInt(weekDay.getWeekDayCode());
                    //第几节
                    Integer period = periodScheme.getPeriod();
                    //学时code
                    String code = weekDay.getWeekDayCode() + String.format("%02d", period);
                    //是否属于禁排
                    Integer isProhibit = timeProhibit.contains(code) ? 1 : 0;
                    //名字格式修改
                    String name = "周" + weekDay.getWeekDayCode() + "第" + period + "节";
                    periodCode.add(ArrangePeriod.builder().campusId(campusId).timeCode(code).codeName(name).dayNo(dayNo).periodType(periodScheme.getPeriodType()).period(period).isProhibit(isProhibit).build());

                });

            });
        }
        return periodCode;
    }

    @Override
    public List<ArrangeRoomRuleDto> getArrangeRoomProhibit(Integer taskId, String schoolId, String term, String campusId, String collegeId) {
        //学院id为null，则去掉禁排规则
//        if (ObjUtil.isNull(collegeId)) {
//            return new ArrayList<>();
//        }
        List<ArrangeRoomRuleDto> arrangeRoomRule = ruleTimeProhibitMapper.getArrangeRoomRuleByTaskId(taskId, ProhibitType.ROOM.getCode(), collegeId);
        return arrangeRoomRule;
    }

    @Override
    public List<ArrangeTeacherRuleDto> getArrangeTeacherTime(Integer taskId, String collegeId) {
        //学院id为null，则去掉禁排规则
//        if (ObjUtil.isNull(collegeId)) {
//            return new ArrayList<>();
//        }
        List<ArrangeTeacherRuleDto> arrangeTeacherRule = ruleTimeProhibitMapper.getArrangeTeacherRuleByTaskId(taskId, ProhibitType.TEACHER.getCode(), collegeId);
        return arrangeTeacherRule;
    }

    @Override
    public List<ArrangeCourseRuleDto> getArrangeCourseProhibit(Integer taskId, String collegeId) {
        List<ArrangeCourseRuleDto> arrangeCourseRule = ruleTimeProhibitMapper.getArrangeCourseRuleByTaskId(taskId, ProhibitType.TEACHINGCLASS.getCode(), null);
        return arrangeCourseRule;
    }

    @Override
    public List<ArrangeScheduleDto> getLockSchedule(Integer taskId, String campusId, Integer isLocked, Integer majorProp, String collegeId, List<ArrangeTeachingClassDto> teachingClassDtoList) {
        List<ArrangeScheduleDto> scheduleLocked = new ArrayList<>();
        //本学期其他任务课表
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        List<TaskInfo> taskInfos = taskInfoService.lambdaQuery().eq(TaskInfo::getSchoolId, taskInfo.getSchoolId()).eq(TaskInfo::getTerm, taskInfo.getTerm()).list();
        List<Integer> taskIds = taskInfos.stream().map(TaskInfo::getTaskId).filter(o -> !o.equals(taskId)).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(taskIds)) {
            scheduleLocked = scheduleMapper.getScheduleLockedByIds(taskIds, campusId, isLocked);
        }
        //获取本学院锁定课表及其他学院课表
        scheduleLocked.addAll(scheduleMapper.getScheduleLocked(taskId, campusId, isLocked, collegeId));

        if (CollUtil.isNotEmpty(teachingClassDtoList)) {
            teachingClassDtoList = teachingClassDtoList.stream().filter(o -> StrUtil.isEmpty(o.getUniqueShiftSign())).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(teachingClassDtoList)) {
                scheduleLocked.addAll(scheduleMapper.addRuleSchedule(teachingClassDtoList));
            }
        }

        if (CollUtil.isEmpty(scheduleLocked)) {
            return scheduleLocked;
        }
        //补充教师信息
        List<Long> teachingClassIds = scheduleLocked.stream().map(ArrangeScheduleDto::getTeachingClassId).collect(Collectors.toList());
        Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds)
                .stream().collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));
        scheduleLocked.forEach(o -> {
            //补充codeName
            o.setCodeName(TimeCodeUtil.convert(o.getTimeCode()));
            //补充教师信息 单独添加，因为教师业务以后可能会变化
            List<TeacherDto> teachers = teachingClassToTeacher.getOrDefault(o.getTeachingClassId(), new ArrayList<>())
                    .stream().filter(t -> Objects.equals(t.getHourType(), o.getHourType()))
                    .collect(Collectors.toList());

            if (CollUtil.isNotEmpty(teachers)) {
                String teacherIds = StrUtil.join(",", teachers.stream().map(TeacherDto::getTeacherId).collect(Collectors.toList()));
                o.setTeacherIds(teacherIds);
            }
        });
        return scheduleLocked;
    }

    @Override
    public void addBathSchedule(Integer taskId, List<Schedule> schedules, String collegeId, Integer majorProp) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        //获取本学期任务
        List<Integer> taskIds = taskInfoService.lambdaQuery().eq(TaskInfo::getSchoolId, taskInfo.getSchoolId()).eq(TaskInfo::getTerm, taskInfo.getTerm()).list()
                .stream().map(TaskInfo::getTaskId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(taskIds)) {
            scheduleMapper.delete(new LambdaUpdateWrapper<Schedule>().in(Schedule::getTaskId, taskIds).eq(ObjUtil.isNotNull(collegeId) && ObjUtil.isNotNull(majorProp), Schedule::getCollegeId, collegeId));
        }
        //批量插入课表，大数据批量插入
        Consumer<List<Schedule>> scheduleConsumer = o -> scheduleMapper.addBatch(o);
        BatchInsert.batchSplitInsert(schedules, scheduleConsumer);
    }

    @Override
    public void addBatchScheduleConflict(Integer taskId, List<ScheduleConflictInfo> scheduleConflicts, List<Long> roomIds) {
        //需要先清除原来的冲突
//        if (CollUtil.isNotEmpty(roomIds)) {
//            scheduleConflictInfoMapper.delete(new LambdaUpdateWrapper<ScheduleConflictInfo>().eq(ScheduleConflictInfo::getTaskId, taskId).in(ScheduleConflictInfo::getRoomId, roomIds));
//        }
        scheduleConflictInfoMapper.delete(new LambdaUpdateWrapper<ScheduleConflictInfo>().eq(ScheduleConflictInfo::getTaskId, taskId));
        //批量插入课表，大数据批量插入
        Consumer<List<ScheduleConflictInfo>> scheduleConflictConsumer = o -> scheduleConflictInfoMapper.addBatch(o);
        BatchInsert.batchSplitInsert(scheduleConflicts, scheduleConflictConsumer);
    }

    @Override
    public void updateScheduleState(List<ArrangeTeachingClassUpdate> arrangeTeachingClassUpdates) {
        //todo 可以根据排课状态批量更新
        List<TeachingClass> teachingClassList = BeanUtil.copyToList(arrangeTeachingClassUpdates, TeachingClass.class);
        teachingClassService.updateBatchById(teachingClassList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Boolean allToTeachingClassUnit(Integer taskId, String baseCollegeId) {
//        Long count = this.lambdaQuery().eq(Schedule::getTaskId, taskId)
//                .count();
//        if (count != 0) {
//            return true;
//        }

        RLock lock = redissonClient.getLock(GlobalConstant.REDIS_PREFIX + taskId + ":" + "allToTeachingClassUnit");
        lock.lock(60, TimeUnit.SECONDS);

//        synchronized (this) {
        try {

//            count = this.lambdaQuery().eq(Schedule::getTaskId, taskId)
//                    .count();
//            if (count != 0) {
//                return true;
//            }

            //所有排课状态 未排  但需要的教学班
            List<GenerateTeachingClassUnitInput> unArranges =
                    teachingClassMapper.getAllUnArrangeTeachingClass(taskId, ScheduleState.UNARRANGE.getCode(),baseCollegeId);
            unArranges = unArranges.stream().filter(o -> StrUtil.isNotEmpty(o.getWeek())
                    && (o.getWeekNum() != null && o.getWeekNum() != 0)
                    && o.getConnectSection() != null).collect(Collectors.toList());
            if (CollUtil.isEmpty(unArranges)) {
                return true;
            }
            List<Long> tcIds = unArranges.stream().map(GenerateTeachingClassUnitInput::getTeachingClassId).distinct().collect(Collectors.toList());
            List<ScheduleDto> arranged = baseMapper.getAllScheduleByTeachingClassIds(taskId, tcIds);
            //为空说明没有排 直接生成原始数据
            if (CollUtil.isEmpty(arranged)) {
                generateTeachingClassUnit(taskId, unArranges);
            } else {
                //排除  排了一半  但是状态也是 未排的教学班
                List<GenerateTeachingClassUnitInput> add = new ArrayList<>();

                Map<Long, List<ScheduleDto>> scheduleMap = arranged.stream()
                        .collect(Collectors.groupingBy(ScheduleDto::getTeachingClassId));
                for (GenerateTeachingClassUnitInput unArrange : unArranges) {
                    List<ScheduleDto> schedules = scheduleMap.get(unArrange.getTeachingClassId());
                    if (CollUtil.isEmpty(schedules)) {
                        //没有课表 直接生成
                        add.add(unArrange);
                        continue;
                    }
                    //不存在课表  生成
                    if (!schedules.stream().map(ScheduleDto::getHourType)
                            .collect(Collectors.toList())
                            .contains(unArrange.getHourType())) {
                        add.add(unArrange);
                    }
                }

                if (CollUtil.isNotEmpty(add)) {
                    generateTeachingClassUnit(taskId, add);
                }
            }
        } catch (Exception e) {
            log.error("教学班转换成课表异常", e);
            throw new BizException("教学班转换成课表异常");
        } finally {
            lock.unlock();
        }

        return true;
    }

    /**
     * @param taskId:
     * @param generateTeachingClassUnits:
     * @Description: 生成教学班课表初始数据
     * @Author: liufeng
     * @Date: 2023/12/21 9:47
     * @return:
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public List<Schedule> generateTeachingClassUnit(Integer taskId, List<GenerateTeachingClassUnitInput> generateTeachingClassUnits) {
        //待生成初始化课表
        List<Schedule> scheduleList = new ArrayList<>();
        GenerateSchedulingData generateSchedulingData = new GenerateSchedulingData();
        List<ArrangeTeachingClassDto> teachingClassList = BeanUtil.copyToList(generateTeachingClassUnits, ArrangeTeachingClassDto.class);
        teachingClassList.forEach(o -> {
            if (StrUtil.isNotEmpty(o.getUniqueShiftSign())) {
                o.setConnectSection(1);
                o.setConnectNumber(1);
            }
        });
        LinkedList<TeachingClassUnit> teachingClassUnits = generateSchedulingData.convertToTeachingClassUnit(taskId, teachingClassList, 0);
        List<TeachingClassUnit> normal = teachingClassUnits.stream().filter(o -> StrUtil.isEmpty(o.getUniqueShiftSign())).collect(Collectors.toList());
        normal.forEach(a -> {
            String uuid = UUID.randomUUID().toString();
            for (int i = 0; i < a.getConnectSection(); i++) {
                scheduleList.add(new Schedule().setTaskId(taskId)
                        .setTeachingClassId(a.getTeachingClassId())
                        .setTeachingClassName(a.getTeachingClassName())
                        .setCourseId(a.getCourseId())
                        .setCourseName(a.getCourseName())
                        .setHourType(a.getTeachingType())
                        .setWeek(a.getClassWeeks())
                        .setRoomId(a.getRoomId() == null ? null : a.getRoomId())
                        .setRoomType(a.getRoomType())
                        .setConnectSection(a.getConnectSection())
                        .setTimeGroup(uuid)
                        .setPreGroup(uuid)
                        .setCollegeId(a.getCollegeId())
                        .setFlag(0));
            }
        });

        List<TeachingClassUnit> sub = teachingClassUnits.stream().filter(o -> StrUtil.isNotEmpty(o.getUniqueShiftSign())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(sub)) {
            List<SubClassGroup> subGroupList = arrangeCourseDataSource.getSubGroupList(taskId, null);
            Iterator<SubClassGroup> iterator = subGroupList.iterator();
            while (iterator.hasNext()) {
                SubClassGroup subGroup = iterator.next();
                for (TeachingClassUnit a : sub) {
                    if (StrUtil.isEmpty(a.getSplitClassGroupId())
                            && Objects.equals(a.getTeachingClassId(), subGroup.getTeachingClassId())
                            && a.getUniqueShiftSign().equals(subGroup.getUniqueShiftSign())
                            && subGroup.getHourTypeList().contains(a.getTeachingType())
                            && Objects.equals(a.getIsSingle(), subGroup.getIsSingle())
                            && Objects.equals(a.getCourseId(), subGroup.getCourseId())) {

                        Iterator<Integer> hourTypeIterator = subGroup.getHourTypeList().iterator();
                        while (hourTypeIterator.hasNext()) {
                            Integer hourType = hourTypeIterator.next();
                            if (Objects.equals(hourType, a.getTeachingType())) {
                                hourTypeIterator.remove();
                                break;
                            }
                        }
                        String uuid = UUID.randomUUID().toString();
                        scheduleList.add(new Schedule().setTaskId(taskId)
                                .setTeachingClassId(a.getTeachingClassId())
                                .setTeachingClassName(a.getTeachingClassName())
                                .setCourseId(a.getCourseId())
                                .setCourseName(a.getCourseName())
                                .setHourType(a.getTeachingType())
                                .setWeek(a.getClassWeeks())
                                .setRoomId(a.getRoomId() == null ? null : a.getRoomId())
                                .setRoomType(a.getRoomType())
                                .setConnectSection(a.getConnectSection())
                                .setCollegeId(a.getCollegeId())
                                .setTimeGroup(uuid)
                                .setPreGroup(uuid)
                                .setFlag(0)
                                .setUniqueGroupSign(subGroup.getUniqueGroupSign()));
                        Integer weekNum = subGroup.getWeekNum();
                        if (weekNum == 1) {
                            iterator.remove();
                            break;
                        } else {
                            subGroup.setWeekNum(weekNum - 1);
                        }
                    }
                }
            }

        }

        if (scheduleList.size() > 0) {
            //批量插入课表，大数据批量插入
            Consumer<List<Schedule>> scheduleConsumer = o -> scheduleMapper.addBatch(o);
            BatchInsert.batchSplitInsert(scheduleList, scheduleConsumer);
//            this.saveBatch(scheduleList);
        }
        return scheduleList;
    }

    @Override
    public OwnerTeachingClassTree teachingClassTreeOwner(Integer taskId, String baseCollegeId, String keyword) {

        RuleUsable ruleUsable = ruleUsableService.lambdaQuery()
                .eq(RuleUsable::getTaskId, taskId)
                .eq(RuleUsable::getCode, 6)
                .one();
        if (ruleUsable == null) {
            return new OwnerTeachingClassTree();
        }
        String rule = ruleUsable.typeToStrong();
        List<TeachingClass> allTeachingClass = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .eq(TeachingClass::getIsEnable, 0)
                .eq(TeachingClass::getFlag, 1)
                .eq(TeachingClass::getIsOptional, 0)
                .orderByAsc(TeachingClass::getTeachingClassName)
                .list();

        if (StrUtil.isEmpty(baseCollegeId)) {
            allTeachingClass = allTeachingClass.stream().filter(o ->
                    (rule.charAt(0) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
                            || (rule.charAt(1) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
                            || (rule.charAt(2) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
                            || (rule.charAt(3) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
            ).collect(Collectors.toList());
        } else {
            allTeachingClass = allTeachingClass.stream()
                    .filter(o -> o.getBaseCollegeId().equals(baseCollegeId) &&
                            ((rule.charAt(0) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
                                    || (rule.charAt(1) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
                                    || (rule.charAt(2) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
                                    || (rule.charAt(3) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 2))
                    ).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(allTeachingClass)) {
            return new OwnerTeachingClassTree();
        }
        List<String> subIds = allTeachingClass.stream().filter(o -> StrUtil.isNotEmpty(o.getUniqueShiftSign()))
                .map(TeachingClass::getUniqueShiftSign).distinct().collect(Collectors.toList());
        if (CollUtil.isNotEmpty(subIds)) {
            allTeachingClass = allTeachingClass.stream().filter(o -> StrUtil.isEmpty(o.getUniqueShiftSign())).collect(Collectors.toList());
            List<TeachingClass> subClass = teachingClassService.lambdaQuery()
                    .eq(TeachingClass::getTaskId, taskId)
                    .eq(TeachingClass::getIsEnable, 0)
                    .eq(TeachingClass::getFlag, 1)
                    .eq(TeachingClass::getIsOptional, 0)
                    .in(TeachingClass::getUniqueShiftSign, subIds)
                    .list();
            if (CollUtil.isNotEmpty(subClass)) {
                allTeachingClass.addAll(subClass);
            }
        }
        List<Long> tcIds = allTeachingClass.stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());
        Map<Long, List<TeachingClassWeek>> weekMap = teachingClassWeekService.lambdaQuery()
                .in(TeachingClassWeek::getTeachingClassId, tcIds)
                .isNotNull(TeachingClassWeek::getWeekNum)
                .ne(TeachingClassWeek::getWeekNum,0)
                .list()
                .stream().collect(Collectors.groupingBy(TeachingClassWeek::getTeachingClassId));
        allTeachingClass.forEach(o -> o.setTeachingClassWeeks(weekMap.get(o.getTeachingClassId())));

        return teachingClassTreeOwner(taskId, keyword, allTeachingClass);
    }

    private OwnerTeachingClassTree teachingClassTreeOwner(Integer taskId, String keyword, List<TeachingClass> allTeachingClass) {
        OwnerTeachingClassTree res = new OwnerTeachingClassTree();
        List<TeachingClass> commClasses = allTeachingClass.stream().filter(o -> StrUtil.isEmpty(o.getUniqueShiftSign())).collect(Collectors.toList());
        List<TeachingClass> subClasses = allTeachingClass.stream().filter(o -> StrUtil.isNotEmpty(o.getUniqueShiftSign())).collect(Collectors.toList());

        CommonTeachingClass commonTeachingClass = new CommonTeachingClass();
        if (CollUtil.isNotEmpty(commClasses)) {
//            Map<String,List<TeachingClassWeek>> stateMap = new HashMap<>();
//
//            commClasses.forEach(o -> {
//                String uuid = o.getSplitTeacherUuid();
//                if (StrUtil.isNotEmpty(uuid)) {
//                    List<TeachingClassWeek> list = stateMap.getOrDefault(uuid, new ArrayList<>());
//                    list.addAll(o.getTeachingClassWeeks());
//                    stateMap.put(uuid,list);
//                }
//            });
//
//            List<TeachingClass> list = new ArrayList<>();
//            HashSet<String> set = new HashSet<>();
//            for (TeachingClass o : commClasses) {
//                if (StrUtil.isEmpty(o.getSplitTeacherUuid())) {
//                    list.add(o);
//                    continue;
//                }
//                if (!set.contains(o.getSplitTeacherUuid())) {
//                    list.add(o);
//                    o.setTeachingClassWeeks(stateMap.get(o.getSplitTeacherUuid()));
//                    set.add(o.getSplitTeacherUuid());
//                }
//            }
//            commClasses = list;

            if (StrUtil.isNotEmpty(keyword)) {
                commClasses = commClasses.stream()
                        .filter(o -> o.getTeachingClassName().contains(keyword)
                                || o.getCourseName().contains(keyword))
                        .collect(Collectors.toList());
            }
            List<CourseTeachingClass> courseTeachingClassList = commonTeachingClass.getCourseTeachingClassList();
            for (TeachingClass commClass : commClasses) {
                Long courseId = commClass.getCourseId();
                String courseName = commClass.getCourseName();
                long count = commClass.getTeachingClassWeeks().stream().filter(o -> o.getScheduleState() != ScheduleState.NORMAL.getCode()).count();
                commClass.setScheduleState(count == 0 ? 1 : 4);
                commClass.setState(count == 0);
                CourseTeachingClass courseTeachingClass = null;
                for (CourseTeachingClass c : courseTeachingClassList) {
                    if (c.getCourseId().equals(courseId)) {
                        courseTeachingClass = c;
                        break;
                    }
                }
                if (courseTeachingClass == null) {
                    courseTeachingClass = new CourseTeachingClass();
                    courseTeachingClass.setCourseId(courseId);
                    courseTeachingClass.setName(courseName);
                    courseTeachingClass.setTeachingClassList(new ArrayList<>());
                    courseTeachingClassList.add(courseTeachingClass);
                }
                courseTeachingClass.getTeachingClassList().add(commClass);
                courseTeachingClass.setNumber(courseTeachingClass.getNumber() + 1);
                commonTeachingClass.setNumber(commonTeachingClass.getNumber() + 1);
                courseTeachingClass.setState(commClass.getScheduleState() == ScheduleState.NORMAL.getCode() && courseTeachingClass.getState());
                commonTeachingClass.setState(commClass.getScheduleState() == ScheduleState.NORMAL.getCode() && commonTeachingClass.getState());
            }
        }
        res.setCommonTeachingClass(commonTeachingClass);

        GroupTeachingClass groupTeachingClass = new GroupTeachingClass();
        if (CollUtil.isNotEmpty(subClasses)) {
            List<String> subIds = subClasses.stream().map(TeachingClass::getUniqueShiftSign).distinct().collect(Collectors.toList());
            List<SubClassGroup> subGroupList = subClassGroupService.lambdaQuery()
                    .eq(SubClassGroup::getTaskId, taskId)
                    .in(SubClassGroup::getUniqueShiftSign, subIds)
                    .like(StrUtil.isNotEmpty(keyword), SubClassGroup::getGroupName, keyword)
                    .list();
            List<Long> tcIds = subClasses.stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());
            List<Schedule> scheduleList = this.lambdaQuery()
                    .in(Schedule::getTeachingClassId, tcIds)
                    .list();
            if (CollUtil.isNotEmpty(subGroupList)) {
                Map<String, List<SubClassGroup>> subGroupMap = subGroupList.stream().collect(Collectors.groupingBy(SubClassGroup::getUniqueShiftSign));

                List<SubClass> subList = subClassService.lambdaQuery()
                        .eq(SubClass::getTaskId, taskId)
                        .in(SubClass::getUniqueShiftSign, subGroupList.stream().map(SubClassGroup::getUniqueShiftSign).collect(Collectors.toList()))
                        .list();

                List<SubClassTreeVo> subClassTreeVoList = groupTeachingClass.getSubClassTreeVoList();
                for (SubClass subClass : subList) {
                    String subId = subClass.getUniqueShiftSign();
                    String subName = subClass.getSubName();
                    SubClassTreeVo subClassTreeVo = null;
                    for (SubClassTreeVo c : subClassTreeVoList) {
                        if (c.getSubId().equals(subId)) {
                            subClassTreeVo = c;
                            break;
                        }
                    }
                    if (subClassTreeVo == null) {
                        subClassTreeVo = new SubClassTreeVo();
                        subClassTreeVo.setSubId(subId);
                        subClassTreeVo.setName(subName);
                        subClassTreeVo.setSubClassGroupList(new ArrayList<>());
                        subClassTreeVoList.add(subClassTreeVo);
                    }
                    List<SubClassGroup> subClassGroups = subGroupMap.get(subId);
                    if (CollUtil.isNotEmpty(subClassGroups)) {
                        Map<String, List<SubClassGroup>> groupMap = subClassGroups.stream().collect(Collectors.groupingBy(SubClassGroup::getUniqueGroupSign));
                        Map<Long, TeachingClass> tcMap = subClasses.stream().collect(Collectors.toMap(TeachingClass::getTeachingClassId, Function.identity()));

                        for (Map.Entry<String, List<SubClassGroup>> stringListEntry : groupMap.entrySet()) {
                            String groupId = stringListEntry.getKey();
                            List<SubClassGroup> teachingClassList = stringListEntry.getValue();
                            boolean state = true;
                            for (SubClassGroup subClassGroup : teachingClassList) {
                                TeachingClass teachingClass = tcMap.get(subClassGroup.getTeachingClassId());
//                                long count = teachingClass.getTeachingClassWeeks().stream()
//                                        .filter(o -> o.getTeachingClassId().equals(subClassGroup.getTeachingClassId())
//                                                && subClassGroup.getHourType().contains(String.valueOf(o.getHourType()))
//                                                && o.getScheduleState() != ScheduleState.NORMAL.getCode()).count();

                                long count = scheduleList.stream().filter(o -> o.getUniqueGroupSign().equals(groupId)
                                        && StrUtil.isEmpty(o.getTimeCode())).count();
                                state = state && count == 0;
                            }
                            SubClassGroupTreeVo subClassGroupTreeVo = new SubClassGroupTreeVo();
                            subClassGroupTreeVo.setName(teachingClassList.get(0).getGroupName());
                            subClassGroupTreeVo.setUniqueGroupSign(teachingClassList.get(0).getUniqueGroupSign());
                            subClassGroupTreeVo.setState(state);

                            subClassTreeVo.getSubClassGroupList().add(subClassGroupTreeVo);
                            subClassTreeVo.setNumber(subClassTreeVo.getNumber() + 1);
                            subClassTreeVo.setState(state && subClassTreeVo.getState());
                            groupTeachingClass.setNumber(groupTeachingClass.getNumber() + 1);
                            groupTeachingClass.setState(state && groupTeachingClass.getState());
                        }
                    }


                }
            }
        }
        res.setGroupTeachingClass(groupTeachingClass);
        return res;
    }


    @Override
    public List<CollegeTeachingClassTree> teachingClassTreeSchool(Integer taskId, String keyword) {
        List<CollegeTeachingClassTree> res = new ArrayList<>();
        List<TeachingClass> allTeachingClass = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .eq(TeachingClass::getIsEnable, 0)
                .eq(TeachingClass::getFlag, 1)
                .isNotNull(TeachingClass::getBaseCollegeId)
                .eq(TeachingClass::getIsOptional, 0)
                .orderByAsc(TeachingClass::getTeachingClassName)
                .list();
        if (CollUtil.isEmpty(allTeachingClass)) {
            return res;
        }
        List<Long> tcIds = allTeachingClass.stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());
        Map<Long, List<TeachingClassWeek>> weekMap = teachingClassWeekService.lambdaQuery()
                .in(TeachingClassWeek::getTeachingClassId, tcIds)
                .isNotNull(TeachingClassWeek::getWeekNum)
                .ne(TeachingClassWeek::getWeekNum,0)
                .list()
                .stream().collect(Collectors.groupingBy(TeachingClassWeek::getTeachingClassId));
        allTeachingClass.forEach(o -> o.setTeachingClassWeeks(weekMap.get(o.getTeachingClassId())));
        Map<String, List<TeachingClass>> collegeMap = allTeachingClass.stream().collect(Collectors.groupingBy(TeachingClass::getBaseCollegeId));
        for (Map.Entry<String, List<TeachingClass>> entry : collegeMap.entrySet()) {
            CollegeTeachingClassTree collegeTeachingClassTree = new CollegeTeachingClassTree();
            String key = entry.getKey();
            collegeTeachingClassTree.setBaseCollegeId(key);
            List<TeachingClass> teachingClassList = entry.getValue();
            collegeTeachingClassTree.setName(teachingClassList.get(0).getCollegeName());
            OwnerTeachingClassTree ownerTeachingClassTree = teachingClassTreeOwner(taskId, keyword, teachingClassList);
            collegeTeachingClassTree.setOwnerTeachingClassTree(ownerTeachingClassTree);
            collegeTeachingClassTree.setNumber(ownerTeachingClassTree.getCommonTeachingClass().getNumber() + ownerTeachingClassTree.getGroupTeachingClass().getNumber());
            collegeTeachingClassTree.setState(ownerTeachingClassTree.getCommonTeachingClass().getState() && ownerTeachingClassTree.getGroupTeachingClass().getState());
            res.add(collegeTeachingClassTree);
        }
        return res;
    }

    @Override
    public List<Object> autoArrangement(Integer taskId, String collegeId, Integer majorProp) {
        RLock lock = redissonClient.getLock(GlobalConstant.REDIS_PREFIX + taskId + ":" + "autoArrange");
        lock.lock(600, TimeUnit.SECONDS);
        try {
            arrangeCourseService.algService(taskId, collegeId, majorProp);
        } finally {
            lock.unlock();
        }
        //返回冲突
//        List<ScheduleConflictInfo> scheduleConflictInfos = scheduleConflictInfoMapper.selectList(new LambdaQueryWrapper<ScheduleConflictInfo>().eq(ScheduleConflictInfo::getTaskId, taskId));
//        fillConflict(scheduleConflictInfos);
        return null;
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getTeachingClassSchedule(Integer taskId, List<Long> teachingClassIds) {
//        teachingClassIds = getSplictTeacherTeachingClassIds(teachingClassIds);
        return getTeachingClassAndSchedule(taskId, teachingClassIds);
    }

    private List<Long> getSplictTeacherTeachingClassIds(List<Long> teachingClassIds) {
        HashSet<Long> ids = new HashSet<>(teachingClassIds);
        List<String> uuid = teachingClassMapper.getSplictTeacherUUid(teachingClassIds);
        if (CollUtil.isNotEmpty(uuid)) {
            List<Long> tcIds = teachingClassMapper.getSplictTeacherTeachingClassByUUid(uuid);
            ids.addAll(tcIds);
        }
        return new ArrayList<>(ids);
    }


    @Override
    public List<TeachingClassWeekScheduleDto> getTeachingClassAndSchedule(Integer taskId, List<Long> classIds) {
        if (CollUtil.isEmpty(classIds)) {
            return new ArrayList<>();
        }
        List<TeachingClassWeekScheduleDto> teachingClassList = teachingClassMapper.getTeachingClassSchedule(null, classIds);
        if (CollUtil.isNotEmpty(teachingClassList)) {
            List<Long> teachingClassIds = teachingClassList.stream().map(TeachingClassWeekScheduleDto::getTeachingClassId).collect(Collectors.toList());
            //补充教师信息
            Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds)
                    .stream().collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));

            //学生人数
//            Map<Long, Integer> studentNumMap = teachingClassStudentMapper.getStudentNumber(teachingClassIds)
//                    .stream().collect(Collectors.toMap(TeachingClassCourseDto::getTeachingClassId, TeachingClassCourseDto::getStudentNumber));

            //当前冲突信息
            List<ScheduleConflictInfo> cnoflictList = scheduleConflictInfoService.list(
                    new LambdaQueryWrapper<ScheduleConflictInfo>()
                            .eq(ScheduleConflictInfo::getTaskId, taskId)
                            .in(ScheduleConflictInfo::getTeachingClassId, teachingClassIds));
            this.fillConflict(cnoflictList);

            Map<Long, List<ScheduleConflictInfo>> cnoflictMap = cnoflictList.stream()
                    .collect(Collectors.groupingBy(ScheduleConflictInfo::getTeachingClassId));


            //课表信息
            List<ScheduleDto> scheduleDtoList = scheduleMapper.getAllScheduleByTeachingClassIds(taskId, teachingClassIds);


            Map<Long, List<ScheduleDto>> scheduleMap = scheduleDtoList.stream().collect(Collectors.groupingBy(ScheduleDto::getTeachingClassId));

            teachingClassList.forEach(a -> {
                //多教师版本
                List<TeacherDto> teachers = teachingClassToTeacher.getOrDefault(a.getTeachingClassId(), ListUtil.empty());
                teachers = teachers.stream().filter(t -> Objects.equals(t.getHourType(), a.getHourType())).collect(Collectors.toList());
                a.setTeachers(teachers);
                //学生人数
//                a.setStudentNumber(studentNumMap.getOrDefault(a.getTeachingClassId(), 0));
                //冲突
                if (CollUtil.isNotEmpty(cnoflictList)) {
                    List<ScheduleConflictInfo> scheduleConflictInfos = cnoflictMap.get(a.getTeachingClassId());
                    if (CollUtil.isNotEmpty(scheduleConflictInfos)) {
                        a.setConflicts(scheduleConflictInfos.stream()
                                .filter(o -> o.getHourType().equals(a.getHourType()))
                                .collect(Collectors.toList()));
                    }
                }
                String teacherName = teachers.stream().map(TeacherDto::getTeacherName).collect(Collectors.joining(","));
                //课表
                if (CollUtil.isNotEmpty(scheduleDtoList)) {
                    List<ScheduleDto> scheduleDtos = scheduleMap.get(a.getTeachingClassId());
                    if (CollUtil.isNotEmpty(scheduleDtos)) {
                        a.setSchedules(scheduleMap.get(a.getTeachingClassId()).stream()
                                .filter(o -> o.getHourType().equals(a.getHourType())
                                        && StrUtil.isNotEmpty(o.getTimeCode()))
                                .peek(o -> o.setTeacherName(teacherName))
                                .collect(Collectors.toList()));
                    }
                }
            });
        }
        return teachingClassList;
    }

    @Override
    public String getTeachingClassAndScheduleByType(Integer taskId, Long teachingClassId, Integer hourType, String preGroup) {
        List<ScheduleDto> scheduleDtoList = scheduleMapper.getAllScheduleByTeachingClassIds(taskId, Collections.singletonList(teachingClassId));
        List<String> weeks = scheduleDtoList.stream()
                .filter(o -> o.getHourType().equals(hourType)
                        && StrUtil.isNotEmpty(o.getTimeCode())
                        && o.getPreGroup().equals(preGroup))
                .map(ScheduleDto::getWeek).distinct().collect(Collectors.toList());

        return BinaryUtil.binaryORMore(weeks);
    }

    @Override
    public void fillConflict(List<ScheduleConflictInfo> scheduleConflictInfos) {
        //填充冲突字符串
        List<TeachingClass> teachingClassList = new ArrayList<>();
        List<Room> roomList = new ArrayList<>();
        List<Teacher> teacherList = new ArrayList<>();
        List<Student> studentList = new ArrayList<>();
        Map<Integer, List<ScheduleConflictInfo>> scheduleConflictInfoMap = scheduleConflictInfos.stream().collect(Collectors.groupingBy(ScheduleConflictInfo::getConflictType));
        List<Long> clashUnitIds = new ArrayList<>();
        //获取冲突类型 对应实体类
        if (CollUtil.isNotEmpty(scheduleConflictInfoMap.get(ConflictType.TeachingClass.getCode()))) {
            clashUnitIds = scheduleConflictInfoMap.get(ConflictType.TeachingClass.getCode()).stream().map(ScheduleConflictInfo::getClashUnit).collect(Collectors.toList());
            if (!clashUnitIds.isEmpty()) {
                teachingClassList = teachingClassService.listByIds(clashUnitIds);
            }
        }
        if (CollUtil.isNotEmpty(scheduleConflictInfoMap.get(ConflictType.Room.getCode()))) {
            clashUnitIds = scheduleConflictInfoMap.get(ConflictType.Room.getCode()).stream().map(ScheduleConflictInfo::getClashUnit).collect(Collectors.toList());
            if (!clashUnitIds.isEmpty()) {
                roomList = roomMapper.selectBatchIds(clashUnitIds);
            }
        }
        if (CollUtil.isNotEmpty(scheduleConflictInfoMap.get(ConflictType.Teacher.getCode()))) {
            clashUnitIds = scheduleConflictInfoMap.get(ConflictType.Teacher.getCode()).stream().map(ScheduleConflictInfo::getClashUnit).collect(Collectors.toList());
            if (!clashUnitIds.isEmpty()) {
                teacherList = teacherService.listByIds(clashUnitIds);
            }
        }
        if (CollUtil.isNotEmpty(scheduleConflictInfoMap.get(ConflictType.Student.getCode()))) {
            clashUnitIds = scheduleConflictInfoMap.get(ConflictType.Student.getCode()).stream().map(ScheduleConflictInfo::getClashUnit).collect(Collectors.toList());
            if (!clashUnitIds.isEmpty()) {
                studentList = studentService.listByIds(clashUnitIds);
            }
        }

        //字符串填充
        for (ScheduleConflictInfo scheduleConflictInfo : scheduleConflictInfos) {
            if (scheduleConflictInfo.getConflictType() == ConflictType.TeachingClass.getCode()) {
                Optional<TeachingClass> teachingClass = teachingClassList.stream().filter(b -> b.getTeachingClassId().equals(scheduleConflictInfo.getClashUnit())).findFirst();
                teachingClass.ifPresent(aClass -> scheduleConflictInfo.setConflictReason(scheduleConflictInfo.getConflictReason() + aClass.getTeachingClassName()));
            }
            if (scheduleConflictInfo.getConflictType() == ConflictType.Room.getCode()) {
                Optional<Room> room = roomList.stream().filter(b -> b.getRoomId().equals(scheduleConflictInfo.getClashUnit())).findFirst();
                room.ifPresent(value -> scheduleConflictInfo.setConflictReason(scheduleConflictInfo.getConflictReason() + value.getRoomName()));
            }
            if (scheduleConflictInfo.getConflictType() == ConflictType.Teacher.getCode()) {
                Optional<Teacher> teacher = teacherList.stream().filter(b -> b.getTeacherId().equals(scheduleConflictInfo.getClashUnit())).findFirst();
                teacher.ifPresent(value -> scheduleConflictInfo.setConflictReason(value.getTeacherName() + scheduleConflictInfo.getConflictReason() + value.getTeacherName()));
            }
            if (scheduleConflictInfo.getConflictType() == ConflictType.Student.getCode()) {
                Optional<Student> student = studentList.stream().filter(b -> b.getStudentId().equals(scheduleConflictInfo.getClashUnit())).findFirst();
                student.ifPresent(value -> scheduleConflictInfo.setConflictReason(scheduleConflictInfo.getConflictReason() + value.getStudentName() + " 学号" + value.getBaseStudentId()));
            }
        }
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getGroupTeachingClassAndSchedule(Integer taskId, String uniqueGroupSign, String groupName) {
//        GroupTeachingClassWeekScheduleDto res = new GroupTeachingClassWeekScheduleDto();
        List<TeachingClassWeekScheduleDto> res = new ArrayList<>();
        List<SubClassGroup> groups = subClassGroupService.lambdaQuery().eq(SubClassGroup::getTaskId, taskId)
                .eq(SubClassGroup::getUniqueGroupSign, uniqueGroupSign)
                .list();
        if (CollUtil.isEmpty(groups)) {
            return res;
        }
        List<Long> tcIds = groups.stream().map(SubClassGroup::getTeachingClassId).collect(Collectors.toList());
        res = getTeachingClassAndSchedule(taskId, tcIds);
//        Map<Long, SubClassGroup> map = groups.stream().collect(Collectors.toMap(SubClassGroup::getTeachingClassId,Function.identity()));
//        schedule = schedule.stream().filter(o -> {
//            SubClassGroup subClassGroup = map.get(o.getTeachingClassId());
//            return subClassGroup.getHourType().contains(String.valueOf(o.getHourType()));
//        }).collect(Collectors.toList());
//
//        schedule.forEach(o -> {
//            o.setConnectSection(1);
//            o.setSchedules(o.getSchedules().stream()
//                    .filter( s -> uniqueGroupSign.equals(s.getUniqueGroupSign()))
//                    .collect(Collectors.toList()));
//        });
//        res.setUniqueGroupSign(uniqueGroupSign);
//        res.setGroupName(groupName);
//        res.setTeachingClassList(schedule);
        return res;
    }

    @Override
    public PageInfo<VenueSessionVo> getVenueSession(Integer currentPage, Integer pageSize, Integer taskId,
                                                    String weeks, String timeCodes, Integer campusId,
                                                    Integer buildingId, Integer selectRoomType, Long roomId, String keyword,
                                                    ArrangeTeachingClassDto teachingClass, Integer departId,
                                                    Integer conflictCheck, Integer capacityCheck, String collegeId, int outer) {
        List<VenueSessionVo> venueSessionVos = new ArrayList<>();
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        //可用的 场地节次
        LinkedList<TimeslotRoom> timeslotRooms = arrangeCourseService.getAvailableTimeslotRoomListV2(taskInfo.getSchoolId(), taskInfo.getTerm(),
                taskId, Integer.parseInt(weeks, 2) == 0 ? null : weeks, timeCodes, campusId, buildingId, selectRoomType, roomId, keyword, teachingClass, departId, conflictCheck, collegeId, outer);

        if (CollUtil.isEmpty(timeslotRooms)) {
            return new PageInfo<>();
        }


        int preSize = timeslotRooms.size();
        int postSize = timeslotRooms.size();
        if (capacityCheck != null && capacityCheck == 0) {

            timeslotRooms = timeslotRooms.stream()
                    .filter(timeslotRoom -> timeslotRoom.getCapacity() >= teachingClass.getStudentNumber())
                    .collect(Collectors.toCollection(LinkedList::new));

            postSize = timeslotRooms.size();
            if (preSize != 0 && postSize == 0 && departId == 0) {
                throw new BizException(999, "教学班人数(" + teachingClass.getStudentNumber()
                        + ")大于所有可用教室的容量");
            }
        }

        preSize = timeslotRooms.size();
        // 返回连上的场地节次
        List<TimeslotRoom[]> consecutiveSessions = findConsecutiveSessions(timeslotRooms, teachingClass.getConnectSection());
        consecutiveSessions.sort(Comparator.comparing(o -> o[0].getWeekSize(), Comparator.reverseOrder()));
        PageInfo<TimeslotRoom[]> pages = PagingUtil.getPages(currentPage, pageSize, consecutiveSessions);
        pages.getList().forEach(consecutiveSession -> {
            //对分组的数据取周次与运算
            String resultWeek = Arrays.stream(consecutiveSession)
                    .map(TimeslotRoom::getWeeks)
                    .reduce(BinaryUtil::binaryAnd)
                    .orElse("");
            //可用节次
            String resultSession = "{}[{}节]";
            String week = TimeCodeUtil.DAY_NAME.get(TimeCodeUtil.DAY_CODE.indexOf(consecutiveSession[0].getTimeslotCode().substring(0, 2)));
            List<Integer> sectionList = Arrays.stream(consecutiveSession).map(a -> Integer.valueOf(a.getTimeslotCode().substring(2))).distinct().sorted().collect(Collectors.toList());
            venueSessionVos.add(new VenueSessionVo()
                    .setRoomId(consecutiveSession[0].getRoomId())
                    .setRoomName(consecutiveSession[0].getRoomName())
                    .setCapacity(consecutiveSession[0].getCapacity())
                    .setWeeks(resultWeek)
                    .setClashWeeks(consecutiveSession[0].getClashWeeks())
                    .setSession(StrUtil.format(resultSession, week, StrUtil.join("、", sectionList)))
                    .setBuildingId(consecutiveSession[0].getBuildingId())
                    .setBuildingName(consecutiveSession[0].getBuildingName())
                    .setTimeCode(Arrays.stream(consecutiveSession).map(TimeslotRoom::getTimeslotCode).collect(Collectors.toList())));
        });
        if (preSize != 0 && venueSessionVos.size() == 0 && departId == 0) {
            throw new BizException(999, "暂无可用连上的节次");
        }

        //适配  有可用的可以拆课表  没有可用的不拆
        boolean canSub = CollUtil.isNotEmpty(timeslotRooms);
        HashSet<String> timeCode = new HashSet<>();
        venueSessionVos.forEach(o -> timeCode.addAll(o.getTimeCode()));

        return new PageInfo<VenueSessionVo>()
                .setCurrentPage(pages.getCurrentPage())
                .setPageSize(pages.getPageSize())
                .setTotal(pages.getTotal())
                .setPages(pages.getPages())
                .setList(venueSessionVos)
                .setCanSub(canSub)
                .setTimeCodes(timeCode.stream().sorted().collect(Collectors.toCollection(LinkedHashSet::new)));
    }

    @Override
    public PageInfo<VenueSessionVo> getVenueSessionSelect(Integer currentPage, Integer pageSize, Integer taskId,
                                                          String weeks, String timeCodes, Integer campusId,
                                                          Integer buildingId, Long roomId, String keyword,
                                                          ArrangeTeachingClassDto teachingClass, Integer departId,
                                                          Integer conflictCheck, Integer capacityCheck, String collegeId) {
        List<VenueSessionVo> venueSessionVos = new ArrayList<>();
        TaskInfo taskInfo = taskInfoService.getById(taskId);

        //教师id问题
        replaceTeacher(taskId, teachingClass);

        //可用的 场地节次
        LinkedList<TimeslotRoom> timeslotRooms = arrangeCourseService.getAvailableTimeslotRoomListSelect(taskInfo.getSchoolId(), taskInfo.getTerm(),
                taskId, Integer.parseInt(weeks, 2) == 0 ? null : weeks, timeCodes, campusId, buildingId, roomId, keyword, teachingClass, departId, conflictCheck, collegeId);

        if (CollUtil.isEmpty(timeslotRooms)) {
            return new PageInfo<>();
        }


        int preSize = timeslotRooms.size();
        int postSize = timeslotRooms.size();
        if (capacityCheck != null && capacityCheck == 0) {

            timeslotRooms = timeslotRooms.stream()
                    .filter(timeslotRoom -> timeslotRoom.getCapacity() >= teachingClass.getStudentNumber())
                    .collect(Collectors.toCollection(LinkedList::new));

            postSize = timeslotRooms.size();
            if (preSize != 0 && postSize == 0 && departId == 0) {
                throw new BizException(999, "教学班人数(" + teachingClass.getStudentNumber()
                        + ")大于所有可用教室的容量");
            }
        }

        preSize = timeslotRooms.size();
        // 返回连上的场地节次
        List<TimeslotRoom[]> consecutiveSessions = findConsecutiveSessions(timeslotRooms, teachingClass.getConnectSection());
        PageInfo<TimeslotRoom[]> pages = PagingUtil.getPages(currentPage, pageSize, consecutiveSessions);
        pages.getList().forEach(consecutiveSession -> {
            //对分组的数据取周次与运算
            String resultWeek = Arrays.stream(consecutiveSession)
                    .map(TimeslotRoom::getWeeks)
                    .reduce(BinaryUtil::binaryAnd)
                    .orElse("");
            //可用节次
            String resultSession = "{}[{}节]";
            String week = TimeCodeUtil.DAY_NAME.get(TimeCodeUtil.DAY_CODE.indexOf(consecutiveSession[0].getTimeslotCode().substring(0, 2)));
            List<Integer> sectionList = Arrays.stream(consecutiveSession).map(a -> Integer.valueOf(a.getTimeslotCode().substring(2))).distinct().sorted().collect(Collectors.toList());
            venueSessionVos.add(new VenueSessionVo()
                    .setRoomId(consecutiveSession[0].getRoomId())
                    .setRoomName(consecutiveSession[0].getRoomName())
                    .setCapacity(consecutiveSession[0].getCapacity())
                    .setWeeks(resultWeek)
                    .setClashWeeks(consecutiveSession[0].getClashWeeks())
                    .setSession(StrUtil.format(resultSession, week, StrUtil.join("、", sectionList)))
                    .setBuildingId(consecutiveSession[0].getBuildingId())
                    .setBuildingName(consecutiveSession[0].getBuildingName())
                    .setTimeCode(Arrays.stream(consecutiveSession).map(TimeslotRoom::getTimeslotCode).collect(Collectors.toList())));
        });
        if (preSize != 0 && venueSessionVos.size() == 0 && departId == 0) {
            throw new BizException(999, "暂无可用连上的节次");
        }

        return new PageInfo<VenueSessionVo>()
                .setCurrentPage(pages.getCurrentPage())
                .setPageSize(pages.getPageSize())
                .setTotal(pages.getTotal())
                .setPages(pages.getPages())
                .setList(venueSessionVos);
    }

    private void replaceTeacher(Integer taskId, ArrangeTeachingClassDto teachingClass) {
        Map<String, Long> teacherMap = teacherService.getSimpleInfo(taskId)
                .stream().collect(Collectors.toMap(Teacher::getBaseTeacherId, Teacher::getTeacherId));

        teachingClass.setTeacherIds(replaceTeacherString(teachingClass.getTeacherIds(), teacherMap));

        for (InnerTeachingClass innerTeachingClass : teachingClass.getTeachingClassList()) {
            innerTeachingClass.setTeacherIds(replaceTeacherString(innerTeachingClass.getTeacherIds(), teacherMap));
        }
    }

    private String replaceTeacherString(String teacherIds, Map<String, Long> teacherMap) {
        if (StrUtil.isNotBlank(teacherIds)) {
            StringBuilder sb = new StringBuilder();
            for (String id : teacherIds.split(",")) {
                if (teacherMap.containsKey(id)) {
                    sb.append(teacherMap.get(id)).append(",");
                } else {
                    sb.append("base-").append(id).append(",");
                }
            }
            return sb.substring(0, sb.length() - 1);
        }
        return "";
    }

    public List<TimeslotRoom[]> findConsecutiveSessions(List<TimeslotRoom> timeslotRoomList, int consecutiveCount) {
        List<TimeslotRoom[]> consecutiveSessions = new ArrayList<>();
        //根据room分组
        Map<Long, List<TimeslotRoom>> groupSessions = timeslotRoomList.stream()
                .collect(Collectors.groupingBy(TimeslotRoom::getRoomId));

        //多班级上课问题
        Map<String, List<TimeslotRoom>> roomGroup = new HashMap<>();
        for (Map.Entry<Long, List<TimeslotRoom>> entry : groupSessions.entrySet()) {
            Long roomId = entry.getKey();
            TimeslotRoom min = Collections.min(entry.getValue(), Comparator.comparingInt(TimeslotRoom::getWeekSize));
            entry.getValue().forEach(o -> {
                o.setWeeks(min.getWeeks());
                o.setWeekSize(min.getWeekSize());
                o.setClashWeeks(min.getClashWeeks());
            });
            for (TimeslotRoom timeslotRoom : entry.getValue()) {
                Integer capacity = timeslotRoom.getCapacity();
                String weeks = timeslotRoom.getWeeks();
                String key = roomId + "-" + capacity + "-" + weeks;
                if (roomGroup.containsKey(key)) {
                    roomGroup.get(key).add(timeslotRoom);
                } else {
                    List<TimeslotRoom> temp = new ArrayList<>();
                    temp.add(timeslotRoom);
                    roomGroup.put(key, temp);
                }
            }
        }

        for (List<TimeslotRoom> timeslotRooms : roomGroup.values()) {
            // 根据 timeCode 进行排序
            timeslotRooms.sort(Comparator.comparing(TimeslotRoom::getTimeslotCode));
            //遍历每一个节次
            for (int i = 0; i < timeslotRooms.size() - consecutiveCount + 1; i++) {
                //选择连着的连上节次判断是否符合要求
                boolean isConsecutive = IntStream.range(i + 1, i + consecutiveCount)
                        .allMatch(j -> Integer.parseInt(timeslotRooms.get(j).getTimeslotCode()) - Integer.parseInt(timeslotRooms.get(j - 1).getTimeslotCode()) == 1);
                //添加上午下午判断
//                boolean isPeriodType = IntStream.range(i + 1, i + consecutiveCount)
//                        .allMatch(j -> timeslotRooms.get(j).getPeriodType().equals(timeslotRooms.get(j - 1).getPeriodType()));

//                if (isConsecutive && isPeriodType) {
                if (isConsecutive) {
                    consecutiveSessions.add(timeslotRooms.subList(i, i + consecutiveCount).toArray(new TimeslotRoom[0]));
                }
            }
        }
        return consecutiveSessions;
    }

    @Override
    public HashSet<String> getGroupVenueSession(Integer currentPage, Integer pageSize, Integer taskId, String weeks, String timeCodes, Integer campusId, Integer buildingId, Long roomId, String keyword, List<ArrangeTeachingClassDto> teachingClassList, Integer departId, Integer conflictCheck, Integer capacityCheck, String collegeId) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        Map<Long, HashSet<String>> map = new HashMap<>(2);
        for (ArrangeTeachingClassDto teachingClass : teachingClassList) {
            //可用的 场地节次
            LinkedList<TimeslotRoom> timeslotRooms = arrangeCourseService.getAvailableTimeslotRoomList(taskInfo.getSchoolId(), taskInfo.getTerm(),
                    taskId, Integer.parseInt(weeks, 2) == 0 ? null : weeks, timeCodes, campusId, buildingId, roomId, keyword, teachingClass, departId, conflictCheck, collegeId, 0);

            if (capacityCheck != null && capacityCheck == 0) {
                int preSize = timeslotRooms.size();

                timeslotRooms = timeslotRooms.stream()
                        .filter(timeslotRoom -> timeslotRoom.getCapacity() >= teachingClass.getStudentNumber())
                        .collect(Collectors.toCollection(LinkedList::new));

                int postSize = timeslotRooms.size();
                if (preSize != 0 && postSize == 0 && departId == 0) {
                    throw new BizException(999, "教学班人数(" + teachingClass.getStudentNumber()
                            + ")大于所有可用教室的容量");
                }
            }

            HashSet<String> timeCode = new HashSet<>();
            timeslotRooms.forEach(o -> timeCode.add(o.getTimeslotCode()));
            map.put(teachingClass.getTeachingClassId(), timeCode);
        }
        HashSet<String> string1 = map.get(teachingClassList.get(0).getTeachingClassId());
        HashSet<String> string2 = map.get(teachingClassList.get(1).getTeachingClassId());

        return CollUtil.intersectionDistinct(string1, string2).stream().sorted().collect(Collectors.toCollection(LinkedHashSet::new));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ScheduleDto> updateVenueSession(List<Schedule> startSchedule, List<Schedule> stopSchedule, Long teachingClassId, Integer hourType) {
        List<Schedule> addSchedule = new ArrayList<>();
        List<Schedule> updateSchedule = new ArrayList<>();
        List<Schedule> deleteSchedule = new ArrayList<>();
        //原来的场地节次 要么更新 都为0时删除。并且每个课表信息应该一致
        if (Integer.parseInt(startSchedule.get(0).getWeek(), 2) == 0) {
            deleteSchedule.addAll(startSchedule);
        } else {
            updateSchedule.addAll(startSchedule);
        }

        Integer taskId = stopSchedule.get(0).getTaskId();

        RLock lock = redissonClient.getLock(GlobalConstant.REDIS_PREFIX + taskId + ":" + "updateVenueSession");
        lock.lock(60, TimeUnit.SECONDS);

        try {
            //新的场地节次 要么新增 要么更新.当存在场地节次一致时，则是更新
            List<Schedule> scheduleList = this.lambdaQuery().eq(Schedule::getTeachingClassId, teachingClassId)
                    .eq(Schedule::getHourType, hourType).list();

            if (CollUtil.isNotEmpty(deleteSchedule)) {
                List<Long> ids = deleteSchedule.stream().map(Schedule::getId).distinct().collect(Collectors.toList());
//            Long count = this.lambdaQuery()
//                    .in(Schedule::getId, ids)
//                    .count();
                long count = scheduleList.stream().filter(o -> ids.contains(o.getId())).count();
                if (count != ids.size()) {
                    throw new BizException("该课表已被调整，请刷新页面");
                }
            }

            scheduleList.forEach(schedule -> {
                if (StrUtil.isNotBlank(schedule.getTimeCode()) && ObjUtil.isNotNull(schedule.getRoomId())) {
                    stopSchedule.forEach(stop -> {
                        //场地节次一致时， 更新周次信息
                        if (schedule.getRoomId().equals(stop.getRoomId()) && schedule.getTimeCode().equals(stop.getTimeCode()) && schedule.getHourType().equals(stop.getHourType())) {
                            stop.setId(schedule.getId());
                            stop.setWeek(BinaryUtil.binaryOR(schedule.getWeek(), stop.getWeek()));
                            updateSchedule.add(stop);
                        }
                    });
                }
            });
            addSchedule = stopSchedule.stream().filter(schedule -> schedule.getId() == null).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(addSchedule)) {
                if (!isArranged(addSchedule)) {
                    this.saveBatch(addSchedule);
                }
            }
            if (CollUtil.isNotEmpty(updateSchedule)) {
                this.updateBatchById(updateSchedule);
            }
            if (CollUtil.isNotEmpty(deleteSchedule)) {
                this.removeByIds(deleteSchedule);
            }
            return scheduleMapper.getAllScheduleByTeachingClassIdAndHourType(teachingClassId, hourType);
        } finally {
            lock.unlock();
        }
    }

    private boolean isArranged(List<Schedule> addSchedule) {
        Integer taskId = addSchedule.get(0).getTaskId();
        Long roomId = addSchedule.get(0).getRoomId();
        List<String> timeCodes = addSchedule.stream().map(Schedule::getTimeCode).distinct().collect(Collectors.toList());
        String week = addSchedule.get(0).getWeek();
        List<Schedule> schedules = this.lambdaQuery().eq(Schedule::getTaskId, taskId)
                .eq(Schedule::getRoomId, roomId)
                .in(Schedule::getTimeCode, timeCodes)
                .list();
        Map<String, List<Schedule>> scheduleMap = schedules.stream().collect(Collectors.groupingBy(Schedule::getTimeCode));
        for (Map.Entry<String, List<Schedule>> entry : scheduleMap.entrySet()) {
            List<Schedule> collect = entry.getValue().stream()
                    .filter(o -> BinaryUtil.binaryAnd(week, o.getWeek()).contains("1"))
                    .collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect)) {
                Room room = roomService.getById(roomId);
                if (room.getConcurrentClass() == 1) {
                    throw new BizException("该教室课时已被其他课程抢先占用，请刷新页面");
                }
                if (collect.size() >= room.getConcurrentClass()) {
                    throw new BizException("该教室课时同时上课班级数量已满");
                }
                List<Long> tcIds = collect.stream().map(Schedule::getTeachingClassId).distinct().collect(Collectors.toList());
                List<TeachingClass> teachingClasses = teachingClassService.lambdaQuery().in(TeachingClass::getTeachingClassId, tcIds).list();
                int sum = teachingClasses.stream().mapToInt(TeachingClass::getClassNum).sum();
                Integer classNum = teachingClassService.getById(addSchedule.get(0).getTeachingClassId()).getClassNum();
                if (sum + classNum > room.getRoomNum()) {
                    throw new BizException("该教室课时同时上课人数已满");
                }
            }
        }

        return false;
    }

    @Override
    public List<ScheduleSelectGroup> updateVenueSessionSelect(List<ScheduleSelect> startSchedule, List<ScheduleSelect> stopSchedule,
                                                              String teachingClassId, Integer hourType) {
        List<ScheduleSelect> addSchedule = new ArrayList<>();
        List<ScheduleSelect> updateSchedule = new ArrayList<>();
        List<ScheduleSelect> deleteSchedule = new ArrayList<>();
        //原来的场地节次 要么更新 都为0时删除。并且每个课表信息应该一致
        if (Integer.parseInt(startSchedule.get(0).getWeek(), 2) == 0) {
            deleteSchedule.addAll(startSchedule);
        } else {
            updateSchedule.addAll(startSchedule);
        }

        if (CollUtil.isNotEmpty(deleteSchedule)) {
            List<Long> ids = deleteSchedule.stream().map(ScheduleSelect::getId).distinct().collect(Collectors.toList());
            Long count = this.lambdaQuery()
                    .in(Schedule::getId, ids)
                    .count();
            if (count != ids.size()) {
                throw new BizException("该课表已被调整，请刷新页面");
            }
        }

        //新的场地节次 要么新增 要么更新.当存在场地节次一致时，则是更新
        List<ScheduleSelect> scheduleList = scheduleSelectService.lambdaQuery().eq(ScheduleSelect::getTeachingClassId, teachingClassId)
                .eq(ScheduleSelect::getHourType, hourType).list();
        scheduleList.forEach(schedule -> {
            if (StrUtil.isNotBlank(schedule.getTimeCode()) && ObjUtil.isNotNull(schedule.getRoomId())) {
                stopSchedule.forEach(stop -> {
                    //场地节次一致时， 更新周次信息
                    if (schedule.getRoomId().equals(stop.getRoomId()) && schedule.getTimeCode().equals(stop.getTimeCode()) && schedule.getHourType().equals(stop.getHourType())) {
                        stop.setId(schedule.getId());
                        stop.setWeek(BinaryUtil.binaryOR(schedule.getWeek(), stop.getWeek()));
                        updateSchedule.add(stop);
                    }
                });
            }
        });
        addSchedule = stopSchedule.stream().filter(schedule -> schedule.getId() == null).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(addSchedule)) {
            if (!isArrangedSelect(addSchedule)) {
                scheduleSelectService.saveBatch(addSchedule);
            }
        }
        if (CollUtil.isNotEmpty(updateSchedule)) {
            scheduleSelectService.updateBatchById(updateSchedule);
        }
        if (CollUtil.isNotEmpty(deleteSchedule)) {
            scheduleSelectService.removeByIds(deleteSchedule);
        }
        List<ScheduleSelectGroup> res = new ArrayList<>();
        List<ScheduleSelect> scheduleSelectList = scheduleSelectService.getAllScheduleByTeachingClassIdAndHourType(teachingClassId, hourType);
        Map<String, List<ScheduleSelect>> map = scheduleSelectList.stream().collect(Collectors.groupingBy(ScheduleSelect::getTimeGroup));
        for (Map.Entry<String, List<ScheduleSelect>> entry : map.entrySet()) {
            res.add(new ScheduleSelectGroup()
                    .setGroup(entry.getKey())
                    .setGroupList(entry.getValue()));
        }
        return res;
    }

    private boolean isArrangedSelect(List<ScheduleSelect> addSchedule) {
        Integer taskId = addSchedule.get(0).getTaskId();
        Long roomId = addSchedule.get(0).getRoomId();
        List<String> timeCodes = addSchedule.stream().map(ScheduleSelect::getTimeCode).distinct().collect(Collectors.toList());
        String week = addSchedule.get(0).getWeek();
        List<Schedule> schedules = this.lambdaQuery().eq(Schedule::getTaskId, taskId)
                .eq(Schedule::getRoomId, roomId)
                .in(Schedule::getTimeCode, timeCodes)
                .list();
        if (schedules.stream().anyMatch(o -> BinaryUtil.binaryAnd(week, o.getWeek()).contains("1"))) {
            throw new BizException("该教室课时已被其他课程抢先占用，请刷新页面");
        }
        List<ScheduleSelect> scheduleSelects = scheduleSelectService.lambdaQuery().eq(ScheduleSelect::getTaskId, taskId)
                .eq(ScheduleSelect::getRoomId, roomId)
                .in(ScheduleSelect::getTimeCode, timeCodes)
                .list();
        if (scheduleSelects.stream().anyMatch(o -> BinaryUtil.binaryAnd(week, o.getWeek()).contains("1"))) {
            throw new BizException("该教室课时已被其他课程抢先占用，请刷新页面");
        }
        return false;
    }

    @Override
    public void removeSchedule(Integer taskId, List<Schedule> scheduleList) {
        if (CollUtil.isEmpty(scheduleList)) {
            throw new BizException("删除课表为空");
        }
        Schedule item = scheduleList.get(0);
        List<Schedule> preSchedules = scheduleService.lambdaQuery()
                .eq(Schedule::getTeachingClassId, item.getTeachingClassId())
                .eq(Schedule::getHourType, item.getHourType())
                .eq(Schedule::getPreGroup, item.getPreGroup())
                .isNull(Schedule::getTimeCode)
                .list();
        //删除课表timeCode和教室id
        TeachingClassWeek teachingClassWeek = teachingClassWeekService.lambdaQuery()
                .eq(TeachingClassWeek::getTeachingClassId, item.getTeachingClassId())
                .eq(TeachingClassWeek::getHourType, item.getHourType())
                .one();
        Long roomId = teachingClassWeek.getRoomId();
        scheduleList.forEach(o -> {
            o.setTimeCode(null);
            o.setRoomId(roomId);
        });
        if (CollUtil.isEmpty(preSchedules)) {
            baseMapper.removeSchedule(roomId, scheduleList);
        } else {
            List<String> weeks = preSchedules.stream().map(Schedule::getWeek).distinct().collect(Collectors.toList());
            weeks.add(item.getWeek());
            String week = BinaryUtil.binaryORMore(weeks);
            this.removeBatchByIds(preSchedules);
            List<Long> ids = scheduleList.stream().map(Schedule::getId).distinct().collect(Collectors.toList());
            this.lambdaUpdate()
                    .set(Schedule::getTimeCode, null)
                    .set(Schedule::getRoomId, roomId)
                    .set(Schedule::getWeek, week)
                    .in(Schedule::getId, ids)
//                    .set(Schedule::getTimeGroup,item.getPreGroup())
                    .update();
        }
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getTeacherUnRange(Integer taskId, String collegeId, Long teacherId, String keyword) {
        List<TeachingClassWeekScheduleDto> list = teachingClassMapper.getClassByTeacher(taskId, collegeId, teacherId, keyword);
        RuleUsable ruleUsable = ruleUsableService.lambdaQuery()
                .eq(RuleUsable::getTaskId, taskId)
                .eq(RuleUsable::getCode, 6)
                .one();
        if (ruleUsable == null) {
            throw new BizException("管理员未设置排课规则");
        }
        String rule = ruleUsable.typeToStrong();
        if (StrUtil.isNotEmpty(collegeId)) {
            //已经过滤学院
            list = list.stream().filter(o ->
                    (rule.charAt(0) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
                            || (rule.charAt(1) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
                            || (rule.charAt(2) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
                            || (rule.charAt(3) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
            ).collect(Collectors.toList());
        }
//        else {
//
//            list = list.stream().filter(o ->
//                    (rule.charAt(0) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
//                            || (rule.charAt(1) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
//                            || (rule.charAt(2) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
//                            || (rule.charAt(3) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
//            ).collect(Collectors.toList());
//        }
        if (CollUtil.isNotEmpty(list)) {
            List<Long> tcIds = list.stream().map(TeachingClassWeekScheduleDto::getTeachingClassId).distinct().collect(Collectors.toList());
            List<TeachingClassWeek> unRanges = teachingClassWeekService.lambdaQuery().in(TeachingClassWeek::getTeachingClassId, tcIds)
                    .ne(TeachingClassWeek::getScheduleState, ScheduleState.NORMAL.getCode())
                    .list();

            list = list.stream()
                    .filter(o -> unRanges.stream()
                            .anyMatch(w -> w.getTeachingClassId().equals(o.getTeachingClassId())
                                    && w.getHourType().equals(o.getHourType())))
                    .collect(Collectors.toList());
        }
        return list;
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getRoomUnRange(Integer taskId, String collegeId, Long roomId, String keyword) {
        List<TeachingClassWeekScheduleDto> list = new ArrayList<>();
        list = teachingClassMapper.getClassByRoom(taskId, collegeId, roomId, keyword);

        List<Long> ids = new ArrayList<>();
//        ids.addAll(scheduleService.lambdaQuery()
//                .eq(Schedule::getTaskId, taskId)
//                .eq(Schedule::getRoomId, roomId)
//                .list().stream().map(Schedule::getTeachingClassId).distinct()
//                .collect(Collectors.toList()));
//        ids.addAll(list.stream().map(TeachingClassWeekScheduleDto::getTeachingClassId).distinct()
//                .collect(Collectors.toList()));
//        if (CollUtil.isNotEmpty(ids)){
//            list = teachingClassMapper.getUnRangeByIds(ids,collegeId,ScheduleState.NORMAL.getCode());
//        }
        RuleUsable ruleUsable = ruleUsableService.lambdaQuery()
                .eq(RuleUsable::getTaskId, taskId)
                .eq(RuleUsable::getCode, 6)
                .one();
        if (ruleUsable == null) {
            throw new BizException("管理员未设置排课规则");
        }
        String rule = ruleUsable.typeToStrong();
        if (StrUtil.isNotEmpty(collegeId)) {
            //已经过滤学院
            list = list.stream().filter(o ->
                    (rule.charAt(0) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
                            || (rule.charAt(1) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
                            || (rule.charAt(2) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
                            || (rule.charAt(3) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
            ).collect(Collectors.toList());
        }
//        else {
//
//            list = list.stream().filter(o ->
//                    (rule.charAt(0) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
//                            || (rule.charAt(1) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
//                            || (rule.charAt(2) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
//                            || (rule.charAt(3) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
//            ).collect(Collectors.toList());
//        }
        return list;
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getTeacherSchedule(Integer taskId, Long teacherId, String timeCodes) {
        List<TeachingClassWeekScheduleDto> teachingClassTeachers = teachingClassMapper.getClassAndHourByTeacher(taskId, teacherId);
        List<TeachingClassWeekScheduleDto> teachingClass = teachingClassService.getTeachingClassAllSchedule(taskId, teachingClassTeachers, timeCodes);
        return teachingClass;
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getRoomSchedule(Integer taskId, Long roomId, String timeCodes) {
        //获取教学班
        List<TeachingClassWeek> teachingClasses = teachingClassMapper.selectListByRoomIdHasWeekNum(taskId, roomId);

        HashSet<Long> ids = new HashSet<>();
        ids.addAll(teachingClasses
                .stream().map(TeachingClassWeek::getTeachingClassId).distinct()
                .collect(Collectors.toList()));

        List<Schedule> schedules = scheduleMapper.selectList(new LambdaQueryWrapper<Schedule>()
                .eq(Schedule::getTaskId, taskId)
                .eq(Schedule::getRoomId, roomId));
        ids.addAll(schedules.stream().map(Schedule::getTeachingClassId).distinct()
                .collect(Collectors.toList()));

        List<TeachingClassWeekScheduleDto> list = getTeachingClassAndSchedule(taskId, new ArrayList<>(ids));

        if (CollUtil.isNotEmpty(list)) {
            List<TeachingClassWeekScheduleDto> res = new ArrayList<>();
            for (TeachingClassWeekScheduleDto item : list) {
                if (schedules.stream().anyMatch(o ->
                        Objects.equals(o.getTeachingClassId(), item.getTeachingClassId())
                                && Objects.equals(o.getHourType(), item.getHourType()))) {
                    List<ScheduleDto> roomSchedules = item.getSchedules().stream()
                            .filter(o -> Objects.equals(o.getRoomId(), roomId) && StrUtil.isNotEmpty(o.getTimeCode()))
                            .collect(Collectors.toList());
                    if (StrUtil.isNotEmpty(timeCodes)) {
                        schedules = schedules.stream()
                                .filter(o -> StrUtil.isNotEmpty(o.getTimeCode()) && timeCodes.contains(o.getTimeCode()))
                                .collect(Collectors.toList());
                    }
                    item.setSchedules(roomSchedules);
                    List<String> scheduleTimeCodes = roomSchedules.stream().map(ScheduleDto::getTimeCode).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(item.getConflicts())) {
                        List<ScheduleConflictInfo> conflicts = item.getConflicts().stream().filter(o -> scheduleTimeCodes.contains(o.getTimeCode())).collect(Collectors.toList());
                        item.setConflicts(conflicts);
                    }
                    res.add(item);
                }
            }
            return res;
        }

        return list;
    }

    @Override
    public List<StudentCollegeTree> getStudentTree(Integer taskId, String keyword) {
//        List<Student> studentList = teachingClassMapper.getTeachingClassStudent(taskId,keyword);
        List<Student> studentList = studentService.getAllStudent(taskId, keyword);
        return Student.toTree(studentList);
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getStudentSchedule(Integer taskId, Long studentId) {
        List<Long> ids = teachingClassStudentMapper.getTeachingClass(taskId, studentId);
        return getTeachingClassAndSchedule(taskId, ids);
    }

    @Override
    public List<StudentCollegeTree> getClassTree(Integer taskId, String keyword) {
        List<Student> studentList = studentService.getClassStudent(taskId, keyword);
        return Student.toTree(studentList);
    }

    @Override
    public List<TeachingClassWeekScheduleDto> getClassSchedule(Integer taskId, String classId) {
        List<Long> ids = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .like(TeachingClass::getToClass, classId)
                .list().stream()
                .map(TeachingClass::getTeachingClassId)
                .distinct().collect(Collectors.toList());
        return getTeachingClassAndSchedule(taskId, ids);
    }

    @Override
    public List<RoomVo> getRoomTree(Integer taskId, String schoolId, String term, String baseCollegeId, Integer module, String keyword) {
        List<Room> roomList = new ArrayList<>();
        if (StrUtil.isNotEmpty(baseCollegeId)) {
            roomList = roomMapper.getCollegeRoom(taskId, baseCollegeId, keyword);
        } else {
            roomList = roomMapper.selectList(
                    new LambdaQueryWrapper<Room>()
                            .eq(Room::getTaskId, taskId)
                            .eq(Room::getIsEnable, 1)
                            .like(StrUtil.isNotEmpty(keyword), Room::getRoomName, keyword));
        }
//        Page<TeachingClassCourseDto> page = new Page<>(1, -1);
//        List<TeachingClassCourseDto> records = teachingClassMapper.getCourseTeachingClassForArrange(page, taskId, null).getRecords();
//
//        List<Schedule> schedules = scheduleService.lambdaQuery()
//                .eq(Schedule::getTaskId, taskId)
//                .list();
//        List<Long> allRoomIds = schedules.stream().map(Schedule::getRoomId).collect(Collectors.toList());
//        roomList = roomList.stream().filter(o -> allRoomIds.contains(o.getRoomId())).collect(Collectors.toList());
//
//        if (module == 1){
//            List<TeachingClassCourseDto> unRange = records.stream()
//                    .filter(o -> o.getState() != ScheduleState.NORMAL.getCode())
//                    .collect(Collectors.toList());
//            RuleUsable ruleUsable = ruleUsableService.lambdaQuery()
//                    .eq(RuleUsable::getTaskId,taskId)
//                    .eq(RuleUsable::getCode, 6)
//                    .one();
//            String rule = ruleUsable.typeToStrong();
//            if (StrUtil.isNotEmpty(baseCollegeId)) {
//                unRange = unRange.stream().filter(o ->
//                        (rule.charAt(0) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
//                                || (rule.charAt(1) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
//                                || (rule.charAt(2) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
//                                || (rule.charAt(3) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
//                ).collect(Collectors.toList());
//            }else {
//                unRange = unRange.stream().filter(o ->
//                        (rule.charAt(0) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
//                                || (rule.charAt(1) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
//                                || (rule.charAt(2) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
//                                || (rule.charAt(3) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
//                ).collect(Collectors.toList());
//            }
//            if (CollUtil.isNotEmpty(unRange)) {
//                List<Long> roomIds = unRange.stream().map(TeachingClassCourseDto::getRoomId).collect(Collectors.toList());
//
//                roomList.forEach(o -> {
//                    if (roomIds.contains(o.getRoomId())) {
//                        o.setScheduleState(false);
//                    }
//                });
//            }
//        }
        return Room.toRoomTree2(roomList);

    }

    @Override
    public PageInfo<AllScheduleVo> getAllTeacherSchedule(Integer taskId, String schoolId, String keyword, String term, String collegeId, Integer currentPage, Integer pageSize) {
        IPage<AllScheduleVo> page = new Page<>(currentPage, pageSize);
        List<ViewSchedule> viewScheduleList = getAllSchedule(taskId, schoolId, term);

        Map<Long, List<ViewSchedule>> teacherSchedulesMap = new HashMap<>();
        viewScheduleList = viewScheduleList.stream().filter(o -> StrUtil.isNotEmpty(o.getTeacherIds())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(viewScheduleList)) {
            Map<String, List<ViewSchedule>> map = viewScheduleList.stream()
                    .collect(Collectors.groupingBy(ViewSchedule::getTeacherIds));
            for (Map.Entry<String, List<ViewSchedule>> entry : map.entrySet()) {
                String teacherKey = entry.getKey();
                if (StrUtil.isNotEmpty(teacherKey)) {
                    for (String teacher : teacherKey.split(",")) {
                        teacherSchedulesMap.computeIfAbsent(Long.valueOf(teacher), k -> new ArrayList<ViewSchedule>())
                                .addAll(entry.getValue());
                    }
                }
            }
        }
        page = teacherService.getAllTeacherPage(new Page<>(currentPage, pageSize), taskId, collegeId, keyword);
        List<AllScheduleVo> teachers = page.getRecords();
        for (AllScheduleVo teacher : teachers) {
            teacher.setSchedules(teacherSchedulesMap.getOrDefault(teacher.getId(), new ArrayList<>()));
        }
        return PagingUtil.formatPageResult(page);
    }

    private List<ViewSchedule> getAllSchedule(Integer taskId, String schoolId, String term) {
        List<Integer> taskIds = Collections.singletonList(taskId);
        if (CollUtil.isEmpty(taskIds)) {
            return null;
        }
        List<ViewSchedule> viewScheduleList = scheduleMapper.getAllSchedule(taskIds);
        if (CollUtil.isNotEmpty(viewScheduleList)) {
            //填充教师
            Map<Long, List<Teacher>> teacherMap = teacherService.lambdaQuery()
                    .eq(Teacher::getSchoolId, schoolId)
                    .eq(Teacher::getTerm, term).list()
                    .stream().collect(Collectors.groupingBy(Teacher::getTeacherId));
            for (ViewSchedule viewSchedule : viewScheduleList) {
                if (StrUtil.isEmpty(viewSchedule.getTeacherIds())) {
                    continue;
                }
                //多教师版本
                String teacherIds = viewSchedule.getTeacherIds();
                for (String teacherId : teacherIds.split(",")) {
                    List<Teacher> teachers = teacherMap.get(Long.valueOf(teacherId));
                    if (CollUtil.isNotEmpty(teachers)) {
                        String name = StrUtil.isEmpty(viewSchedule.getTeacherName()) ?
                                teachers.get(0).getTeacherName()
                                : viewSchedule.getTeacherName() + "," + teachers.get(0).getTeacherName();
                        viewSchedule.setTeacherName(name);
                    }
                }
            }
        }
        return viewScheduleList;
    }

    @Override
    public PageInfo<AllScheduleVo> getAllRoomSchedule(Integer taskId, String schoolId, String term, Integer campusId, Integer buildingId, String keyword, Integer currentPage, Integer pageSize) {
        IPage<AllScheduleVo> page = new Page<>(currentPage, pageSize);
        List<ViewSchedule> viewScheduleList = getAllSchedule(taskId, schoolId, term);
        Map<Long, List<ViewSchedule>> map = new HashMap<>();
        if (CollUtil.isNotEmpty(viewScheduleList)) {
            map = viewScheduleList.stream().collect(Collectors.groupingBy(ViewSchedule::getRoomId));
        }
        page = roomMapper.getAllRoomPage(new Page<>(currentPage, pageSize), taskId, campusId, buildingId, keyword);
        List<AllScheduleVo> rooms = page.getRecords();
        for (AllScheduleVo room : rooms) {
            room.setSchedules(map.getOrDefault(room.getId(), new ArrayList<>()));
        }
        return PagingUtil.formatPageResult(page);
    }

    @Override
    public PageInfo<AllScheduleVo> getAllStudentSchedule(Integer taskId, String schoolId, String term, String gradeId, String classId, String keyword, String collegeId, Integer currentPage, Integer pageSize) {
        IPage<AllScheduleVo> page = new Page<>(currentPage, pageSize);
        List<ViewSchedule> viewScheduleList = getAllScheduleWithStudent(taskId, schoolId, term);

        viewScheduleList = viewScheduleList.stream().filter(o -> StrUtil.isNotEmpty(o.getStudentIds())).collect(Collectors.toList());

        Map<Long, List<ViewSchedule>> stuSchedulesMap = new HashMap<>();
        if (CollUtil.isNotEmpty(viewScheduleList)) {
            Map<String, List<ViewSchedule>> map = viewScheduleList.stream()
                    .collect(Collectors.groupingBy(ViewSchedule::getStudentIds));
            for (Map.Entry<String, List<ViewSchedule>> entry : map.entrySet()) {
                String stuIds = entry.getKey();
                if (StrUtil.isNotEmpty(stuIds)) {
                    for (String stuId : stuIds.split(",")) {
                        stuSchedulesMap.computeIfAbsent(Long.valueOf(stuId), k -> new ArrayList<ViewSchedule>())
                                .addAll(entry.getValue());
                    }
                }
            }


        }
        page = studentService.getAllStudentPage(new Page<>(currentPage, pageSize), taskId, gradeId, classId, keyword, collegeId);
        List<AllScheduleVo> students = page.getRecords();
        for (AllScheduleVo student : students) {
            student.setSchedules(stuSchedulesMap.getOrDefault(student.getId(), new ArrayList<>()));
        }
        return PagingUtil.formatPageResult(page);
    }


    private List<ViewSchedule> getAllScheduleWithStudent(Integer taskId, String schoolId, String term) {
        List<Integer> taskIds = Collections.singletonList(taskId);
        if (CollUtil.isEmpty(taskIds)) {
            return null;
        }
        List<ViewSchedule> viewScheduleList = scheduleMapper.getAllScheduleWithStudent(taskIds);
        if (CollUtil.isNotEmpty(viewScheduleList)) {
            //填充教师
            Map<Long, List<Teacher>> teacherMap = teacherService.lambdaQuery()
                    .eq(Teacher::getSchoolId, schoolId)
                    .eq(Teacher::getTerm, term).list()
                    .stream().collect(Collectors.groupingBy(Teacher::getTeacherId));
            for (ViewSchedule viewSchedule : viewScheduleList) {
                if (StrUtil.isEmpty(viewSchedule.getTeacherIds())) {
                    continue;
                }
                //多教师版本
                String teacherIds = viewSchedule.getTeacherIds();
                for (String teacherId : teacherIds.split(",")) {
                    List<Teacher> teachers = teacherMap.get(Long.valueOf(teacherId));
                    if (CollUtil.isNotEmpty(teachers)) {
                        String name = StrUtil.isEmpty(viewSchedule.getTeacherName()) ?
                                teachers.get(0).getTeacherName()
                                : viewSchedule.getTeacherName() + "," + teachers.get(0).getTeacherName();
                        viewSchedule.setTeacherName(name);
                    }
                }
            }
        }
        return viewScheduleList;
    }

    @Override
    public PageInfo<TeachingClassSegmentVo> getTeachingClassSegmentPage(Integer taskId, Page<TeachingClassSegmentVo> page, String gradeId, String majorId, String type, String keyword, String baseCollegeId) {
        IPage<TeachingClassSegmentVo> teachingClassPage = teachingClassMapper.getSegmentTeachingClassForArrange(page, taskId, gradeId, majorId, type, keyword, baseCollegeId);
        List<TeachingClassSegmentVo> teachingClassList = teachingClassPage.getRecords();
        if (CollUtil.isNotEmpty(teachingClassList)) {
            List<Long> teachingClassIds = teachingClassList.stream().map(TeachingClassSegmentVo::getTeachingClassId).collect(Collectors.toList());
            //补充教师信息
            Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds)
                    .stream().collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));
            //填充周次数据
            List<TeachingClassWeek> teachingClassWeekList = teachingClassWeekService.list(new LambdaQueryWrapper<TeachingClassWeek>().in(TeachingClassWeek::getTeachingClassId, teachingClassIds));
            Map<Long, List<TeachingClassWeek>> weekMap = teachingClassWeekList.stream().collect(Collectors.groupingBy(TeachingClassWeek::getTeachingClassId));


            teachingClassList.forEach(a -> {
                a.setTeachers(teachingClassToTeacher.getOrDefault(a.getTeachingClassId(), new ArrayList<>()));
                //周次
                a.setCourseWeeks(weekMap.get(a.getTeachingClassId()));
            });
        }
        teachingClassPage.setRecords(teachingClassList);
        return PagingUtil.formatPageResult(teachingClassPage);
    }

    @Override
    public List<ViewScheduleDto> getUnRangeSchedule(Integer taskId, Long teachingClassId) {
//        List<Long> teachingClassIds = getSplictTeacherTeachingClassIds(Collections.singletonList(teachingClassId));
        //课表信息
        List<ViewScheduleDto> scheduleDtoList = scheduleMapper.getUnRangeScheduleByTeachingClassIds(taskId, Collections.singletonList(teachingClassId));
        if (CollUtil.isEmpty(scheduleDtoList)) {
            return scheduleDtoList;
        }

        List<String> groups = scheduleDtoList.stream().map(ViewScheduleDto::getTimeGroup).distinct().collect(Collectors.toList());
        Map<String, List<ViewScheduleDto>> groupMap = scheduleMapper.getUnRangeScheduleByTimeGroup(groups).stream().collect(Collectors.groupingBy(ViewScheduleDto::getTimeGroup));

        //补充教师信息
        Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(Collections.singletonList(teachingClassId))
                .stream().collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));

        scheduleDtoList.forEach(a -> {
            //多教师版本
            List<TeacherDto> teachers = teachingClassToTeacher.getOrDefault(a.getTeachingClassId(), ListUtil.empty());
            teachers = teachers.stream().filter(t -> Objects.equals(t.getHourType(), a.getHourType())).collect(Collectors.toList());
            a.setTeachers(teachers);
            //课表
            a.setScheduleList(groupMap.get(a.getTimeGroup()));
        });

        return scheduleDtoList;
    }

    @Override
    public List<GroupViewSchedule> getGroupUnRangeSchedule(Integer taskId, String subId, String subName) {
        List<GroupViewSchedule> res = new ArrayList<>();
        List<SubClassGroup> groups = subClassGroupService.lambdaQuery().eq(SubClassGroup::getTaskId, taskId)
                .eq(SubClassGroup::getUniqueGroupSign, subId)
                .list();
        List<Long> tcIds = groups.stream().map(SubClassGroup::getTeachingClassId).distinct().collect(Collectors.toList());
        //课表信息
        List<ViewScheduleDto> scheduleDtoList = scheduleMapper.getUnRangeScheduleByTeachingClassIds(taskId, tcIds);
        scheduleDtoList = scheduleDtoList.stream().filter(o -> subId.equals(o.getUniqueGroupSign())).collect(Collectors.toList());

        if (CollUtil.isEmpty(scheduleDtoList)) {
            return res;
        }
//        List<String> timeGroups = scheduleDtoList.stream().map(ViewScheduleDto::getTimeGroup).distinct().collect(Collectors.toList());
//        Map<String, List<ViewScheduleDto>> groupMap = scheduleMapper.getUnRangeScheduleByTimeGroup(timeGroups).stream().collect(Collectors.groupingBy(ViewScheduleDto::getTimeGroup));

        //补充教师信息
        Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(tcIds)
                .stream().collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));

        scheduleDtoList.forEach(a -> {
            //多教师版本
            List<TeacherDto> teachers = teachingClassToTeacher.getOrDefault(a.getTeachingClassId(), ListUtil.empty());
            teachers = teachers.stream().filter(t -> Objects.equals(t.getHourType(), a.getHourType())).collect(Collectors.toList());
            a.setTeachers(teachers);

            //课表
//            a.setScheduleList(groupMap.get(a.getTimeGroup()));

        });
        List<Long> courseIds = scheduleDtoList.stream().map(ViewScheduleDto::getCourseId).collect(Collectors.toList());
        Map<Long, List<ViewScheduleDto>> courseMap = scheduleDtoList.stream().collect(Collectors.groupingBy(ViewScheduleDto::getCourseId));
        List<ViewScheduleDto> scheduleDtos = new ArrayList<>(2);
        for (int i = 0; i < scheduleDtoList.size() / 2; i++) {
            scheduleDtos.clear();
            scheduleDtos.add(courseMap.get(courseIds.get(0)).get(i));
            scheduleDtos.add(courseMap.get(courseIds.get(1)).get(i));
            res.add(new GroupViewSchedule().setScheduleList(scheduleDtos)
                    .setSubId(subId)
                    .setSubName(subName));
        }

        return res;
    }

    @Override
    public List<ViewScheduleDto> getTeacherUnRangeSchedule(Integer taskId, Long teacherId, Long teachingClassId) {
        //课表信息
        List<ViewScheduleDto> scheduleDtoList = scheduleMapper.getUnRangeScheduleByTeachingClassIds(taskId, Collections.singletonList(teachingClassId));
        if (CollUtil.isEmpty(scheduleDtoList)) {
            return scheduleDtoList;
        }

        List<String> timeGroups = scheduleDtoList.stream().map(ViewScheduleDto::getTimeGroup).distinct().collect(Collectors.toList());
        Map<String, List<ViewScheduleDto>> groupMap = scheduleMapper.getUnRangeScheduleByTimeGroup(timeGroups).stream().collect(Collectors.groupingBy(ViewScheduleDto::getTimeGroup));

        //补充教师信息
        Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(Collections.singletonList(teachingClassId))
                .stream().collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));

        scheduleDtoList.forEach(a -> {
            //多教师版本
            List<TeacherDto> teachers = teachingClassToTeacher.getOrDefault(a.getTeachingClassId(), ListUtil.empty());
            teachers = teachers.stream().filter(t -> Objects.equals(t.getHourType(), a.getHourType())).collect(Collectors.toList());
            a.setTeachers(teachers);
            //课表
            a.setScheduleList(groupMap.get(a.getTimeGroup()));
        });
        scheduleDtoList = scheduleDtoList.stream()
                .filter(o -> StrUtil.isNotEmpty(o.getTeacherIds())
                        && o.getTeacherIds().contains(String.valueOf(teacherId)))
                .collect(Collectors.toList());
        return scheduleDtoList;
    }

    @Override
    public List<ViewScheduleDto> getRoomUnRangeSchedule(Integer taskId, Long roomId, Long teachingClassId) {
        //课表信息
        List<ViewScheduleDto> scheduleDtoList = scheduleMapper.getUnRangeScheduleByTeachingClassIds(taskId, Collections.singletonList(teachingClassId));
        if (CollUtil.isEmpty(scheduleDtoList)) {
            return scheduleDtoList;
        }

        List<String> groups = scheduleDtoList.stream().map(ViewScheduleDto::getTimeGroup).distinct().collect(Collectors.toList());
        Map<String, List<ViewScheduleDto>> groupMap = scheduleMapper.getUnRangeScheduleByTimeGroup(groups).stream().collect(Collectors.groupingBy(ViewScheduleDto::getTimeGroup));

        //补充教师信息
        Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(Collections.singletonList(teachingClassId))
                .stream().collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));

        scheduleDtoList.forEach(a -> {
            //多教师版本
            List<TeacherDto> teachers = teachingClassToTeacher.getOrDefault(a.getTeachingClassId(), ListUtil.empty());
            teachers = teachers.stream().filter(t -> Objects.equals(t.getHourType(), a.getHourType())).collect(Collectors.toList());
            a.setTeachers(teachers);
            //课表
            a.setScheduleList(groupMap.get(a.getTimeGroup()));
        });
        List<Integer> types = teachingClassWeekService.lambdaQuery()
                .eq(TeachingClassWeek::getTeachingClassId, teachingClassId)
                .eq(TeachingClassWeek::getRoomId, roomId)
                .list().stream().map(TeachingClassWeek::getHourType)
                .collect(Collectors.toList());
        scheduleDtoList = scheduleDtoList.stream()
                .filter(o -> types.contains(o.getHourType()))
                .collect(Collectors.toList());
        return scheduleDtoList;
    }

    @Override
    public String allScheduleToExcel(Integer taskId, Integer type) {
        String modelPath = GlobalConstant.MODEL_EXCEL_PATH + "【模板】课程表信息（大学排课）.xls";

        TaskInfo taskInfo = taskInfoService.getById(taskId);
        String storePath = "/" + taskInfo.getTermName() + "/syncScheduleToBasic" + UUID.randomUUID().toString() + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

        FileUtil.copy(modelPath, targetPath, true);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);
        writer.setSheet(0);
        writer.passCurrentRow();
        writer.passCurrentRow();

        List<SyncScheduleDto> syncScheduleDtos = scheduleMapper.syncScheduleDto(taskId, type);
        //老师
        List<Long> teachingClassIds = syncScheduleDtos.stream().map(SyncScheduleDto::getTeachingClassId).distinct().collect(Collectors.toList());
        Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds).stream()
                .collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));

        //课时方案
        /*
        默认（不设置） 用校区的
        东华用教学楼的课时方案
        七台河用年级的
         */
        Map<Integer, Map<String, String>> campusSchemeMap = new HashMap<>();
        Map<Integer, List<RuleWeekDay>> campusMap = ruleWeekDayService.lambdaQuery().eq(RuleWeekDay::getTaskId, taskId).list().stream()
                .collect(Collectors.groupingBy(RuleWeekDay::getCampusId));
        for (Map.Entry<Integer, List<RuleWeekDay>> entry : campusMap.entrySet()) {
            campusSchemeMap.put(entry.getKey(), campusMap.get(entry.getKey()).stream().collect(Collectors.toMap(RuleWeekDay::getWeekDayCode, RuleWeekDay::getBaseSchemeName)));
        }

        /*
             2、七台河 打包放开
             */
//        List<MajorGrade> gradeScheme = majorGradeMapper.getGradeScheme(taskId);
//        Map<String, List<MajorGrade>> gradeSchemeMap = gradeScheme.stream().collect(Collectors.groupingBy(MajorGrade::getGradeId));

        List<List<String>> rows = new LinkedList<>();
        List<String> row = null;

        for (SyncScheduleDto syncScheduleDto : syncScheduleDtos) {
            if (ObjUtil.isNull(syncScheduleDto.getTimeCode()) || ObjUtil.isNull(syncScheduleDto.getCourseName())) {
                continue;
            }
            row = new LinkedList<>();
            row.add("全部");
            //上课周数
            String weekNum = IntStream.range(0, syncScheduleDto.getWeek().length())
                    .filter(i -> syncScheduleDto.getWeek().charAt(i) == '1')
                    .mapToObj(i -> String.valueOf(i + 1))
                    .collect(Collectors.joining(","));
            row.add(weekNum);
            //星期
            String week = syncScheduleDto.getTimeCode().substring(0, 2);
            row.add(GlobalConstant.dayNameCodeMap.get(week));
            //课时序号
            row.add(String.valueOf(Integer.parseInt(syncScheduleDto.getTimeCode().substring(2))));
            //教室类型大类1,2,3下的，转换为大类上传
            String roomType = "";
//            if ("1234".contains(syncScheduleDto.getRoomType().toString().substring(0, 1))) {
//                roomType = syncScheduleDto.getRoomType().toString().substring(0, 1);
//            }
            row.add(syncScheduleDto.getRoomType().toString());
            row.add(syncScheduleDto.getRoomName());
            row.add(syncScheduleDto.getCourseType());
            row.add(syncScheduleDto.getCourseName());
            row.add(StrUtil.isNotEmpty(syncScheduleDto.getSplitTeacherUuid()) ? SplitTeacherTeachingClass.get(syncScheduleDto.getSplitTeacherUuid())
                    : syncScheduleDto.getTeachingClassName());
            //教师id
            String teachers = teachingClassToTeacher.getOrDefault(syncScheduleDto.getTeachingClassId(), new ArrayList<>())
                    .stream().filter(o -> o.getHourType().equals(syncScheduleDto.getHourType()))
                    .map(TeacherDto::getBaseTeacherId).distinct().collect(Collectors.joining(","));
            row.add(teachers);
            row.add("");

            // TODO: 定制 打包更改 liufeng 2025/6/10 二选一
            /*
             1、东华通用
             */
            String scheme = StrUtil.isNotEmpty(syncScheduleDto.getBaseSchemeName()) ? syncScheduleDto.getBaseSchemeName()
                    : campusSchemeMap.get(syncScheduleDto.getCampusId()).get(week);

            /*
            2 、七台河
             */
//            String scheme = StrUtil.isNotEmpty(syncScheduleDto.getGradeId()) && gradeSchemeMap.containsKey(syncScheduleDto.getGradeId()) ?
//                    gradeSchemeMap.get(syncScheduleDto.getGradeId()).get(0).getBaseSchemeId()
//                    : campusSchemeMap.get(syncScheduleDto.getCampusId()).get(week);
            row.add(scheme);
            row.add(GlobalConstant.hourTypeMap.get(syncScheduleDto.getHourType()));
            rows.add(row);
        }
        writer.write(rows, false);
        writer.close();
        return "/static/OutputExcel/" + storePath;
    }


    //    @Override
    public void exportedVenueSchedule0(HttpServletResponse response, Integer taskId, Long roomId) {

        TaskInfo taskInfo = taskInfoService.getById(taskId);

        Room room = roomMapper.selectById(roomId);

        String fileName = room.getRoomName() + "(" + room.getBuildingName() + ")" + ".xlsx";
        String storePath = taskInfo.getSchoolName() + File.separator + fileName;
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;


        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);
        writer.getStyleSet().setWrapText();

        List<TeachingClassWeekScheduleDto> resultList = scheduleService.getRoomSchedule(taskId, roomId, null);

        int periods = basicRuleService.getMaxPeriod(taskId);
        String title = "{} 教室课表  \n  {}";
        writer.merge(taskInfo.getCycleDay(), StrUtil.format(title, room.getRoomName(), taskInfo.getTermName()), false);
        writer.setRowHeight(0, 40);
        long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();
        long sectionNum = resultList.stream()
                .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
                .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
        String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
        String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
        writer.merge(taskInfo.getCycleDay(), filter, false);
        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}({}) \n{}\n{}\n{}\n{} \n班级人数:{} \n场地容量:{}";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                        String format = StrUtil.format(scheduleHour, item.getCourseName(), Objects.requireNonNull(HourType.getByCode(hourType)).getMsg(),
                                item.getTeachingClassName(), teacherNames, roomName, weekString, item.getClassNum(), byWeekList.get(0).getRoomNum());

                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                        if ("--".equals(s)) {
                            s = "";
                        } else {
                            s += "\n";
                        }
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                    });
                });
            });
        }

        writer.write(rows, false);
        setExcelForm(writer, rows, 2);

        if (null != response) {
            // 下边两行任取一行都可以
            response.addHeader("Content-Type", "application/vnd.ms-excel;charset=UTF-8");
            response.addHeader("Content-Disposition", writer.getDisposition("场地导出.xls", StandardCharsets.UTF_8));
        }
        try {
            writer.flush(response.getOutputStream(), true);
        } catch (IOException e) {
            log.error("场地导出错误" + e);
        }
        writer.close();
    }

    @Override
    public void exportedVenueSchedule(HttpServletResponse response, Integer taskId, Long roomId) {

        TaskInfo taskInfo = taskInfoService.getById(taskId);

        Room room = roomMapper.selectById(roomId);

        String fileName = room.getRoomName() + "(" + room.getBuildingName() + ")" + ".xlsx";
        String storePath = taskInfo.getSchoolName() + File.separator + fileName;
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;


        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);
        writer.getStyleSet().setWrapText();

        List<TeachingClassWeekScheduleDto> resultList = scheduleService.getRoomSchedule(taskId, roomId, null);

        int periods = basicRuleService.getMaxPeriod(taskId);

        String title = "{}教室课表";
        CellStyle header = writer.createCellStyle();
        Font headerFont = writer.createFont();
        headerFont.setFontHeightInPoints((short) 15);
        header.setFont(headerFont);
        header.setAlignment(HorizontalAlignment.CENTER);
        header.setBorderBottom(BorderStyle.THIN);
        header.setBorderLeft(BorderStyle.THIN);
        header.setBorderRight(BorderStyle.THIN);
        header.setBorderTop(BorderStyle.THIN);

        writer.merge(0, 0, 0, taskInfo.getCycleDay(), StrUtil.format(title, taskInfo.getTermName()), header);
        writer.passCurrentRow();

        writer.setRowHeight(0, 40);

        String filterTem = "场地: {}-{} 容量:{}    归属单位: {} ";
        String filter = StrUtil.format(filterTem, room.getBuildingName(), room.getRoomName(), room.getRoomNum(), room.getCollegeName() == null ? "" : room.getCollegeName());
        writer.merge(1, 1, 0, taskInfo.getCycleDay(), filter, header);
        writer.passCurrentRow();

        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}\n{}\n{}\n班级人数:{}\n";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                        String format = StrUtil.format(scheduleHour,
                                item.getTeachingClassName(), teacherNames, weekString, item.getClassNum());

                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                        if ("--".equals(s)) {
                            s = "";
                        } else {
                            s += "\n";
                        }
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                    });
                });
            });
        }

        writer.write(rows, false);

        String time = "导出时间: {} ";
        writer.merge(taskInfo.getCycleDay(), StrUtil.format(time, DateUtil.now()), false);


        setExcelForm(writer, rows, 2);

        if (null != response) {
            // 下边两行任取一行都可以
            response.addHeader("Content-Type", "application/vnd.ms-excel;charset=UTF-8");
            response.addHeader("Content-Disposition", writer.getDisposition("场地导出.xls", StandardCharsets.UTF_8));
        }
        try {
            writer.flush(response.getOutputStream(), true);
        } catch (IOException e) {
            log.error("场地导出错误" + e);
        }
        writer.close();
    }


    /**
     * 格式化
     *
     * @param writer
     * @param rows
     * @param headLine 表头行数
     */
    private void setExcelForm(ExcelWriter writer, List<List<String>> rows, Integer headLine) {
        int start = 0;
        int end = start + 1;
        writer.setColumnWidth(0, 10);
        for (int colIndex = 1; colIndex < rows.get(0).size(); colIndex++) {
            writer.setColumnWidth(colIndex, 20);
            for (int i = 0; i <= rows.size() + 1; i++) {
                if (i < headLine) {
                    writer.setRowHeight(i, 30);
                } else {
                    writer.setRowHeight(i, 100);
                }
            }
            while (start < rows.size()) {
                if (!"--".equals(rows.get(start).get(colIndex))
                        && end < rows.size()
                        && rows.get(start).get(colIndex).equals(rows.get(end).get(colIndex))) {
                    end++;
                } else {
                    if (end - start > 1) {
                        writer.merge(start + headLine, end + headLine - 1, colIndex, colIndex, rows.get(start).get(colIndex), false);
                    }
                    start = end;
                    end = start + 1;
                }
            }
            start = 0;
            end = start + 1;
        }
    }


    @Override
    public void summaryScheduleToExcel(HttpServletResponse response, Integer taskId, Integer scheduleType) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);
        String name = "/全校总表-";
        //1:教室 2:教师 3:行政班 4:教学班
        switch (scheduleType) {
            case 1:
                name = "/全校教室总表-";
                break;
            case 2:
                name = "/全校教师总表-";
                break;
            case 3:
                name = "/全校行政班总表-";
                break;
            case 4:
                name = "/全校教学班总表-";
                break;
            case 5:
                name = "/全校学生总表-";
                break;
        }
        String storePath = "/" + taskInfo.getSchoolName() + name + LocalDate.now() + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;


        FileUtil.del(targetPath);


        //记录该任务所有课时编码
        List<String> timeCodeString = new ArrayList<>();
        String msg = "----";
        if (FixType.getByCode(scheduleType) != null) {
            msg = FixType.getByCode(scheduleType).getMsg();
        }
        String header = msg.substring(0, msg.length() - 2);
        if (scheduleType == 5) {
            header = "学生";
        }
        ExcelWriter writer = ExcelUtil.getWriter(targetPath, header + "总课表");

        //设置表头
        writer.merge(0, 1, 0, 0, header + "/课表", false);


        Integer cycleDay = taskInfo.getCycleDay();
        Integer maxDay = basicRuleService.getMaxPeriod(taskId);
        int l = 1;
        for (int i = 1; i <= cycleDay; i++) {
            int r = l + maxDay - 1;

            writer.merge(0, 0, l, r, GlobalConstant.dayNameCodeMap.get("0" + i), false);
            l = r + 1;
        }

        int a = 1;
        for (int i = 1; i <= cycleDay; i++) {
            int index = 0;
            for (int j = 1; j <= maxDay; j++) {
                writer.writeCellValue(a + index, 1, "第" + j + "节");
                timeCodeString.add(String.format("%02d", i) + String.format("%02d", j));
                index++;
            }
            a = (i * maxDay) + 1;
        }


        writer.getStyleSet().setWrapText();
        writer.setColumnWidth(-1, 30);
        writer.passRows(2);
        //1:教室 2:教师 3:行政班 4:教学班 5:学生
        if (scheduleType == FixType.Class.getCode()) {
            fillClassSummarySchedule(taskId, timeCodeString, writer);
        } else if (scheduleType == FixType.Teacher.getCode()) {
            fillTeacherSummarySchedule(taskId, timeCodeString, writer);
        } else if (scheduleType == FixType.Room.getCode()) {
            fillRoomSummarySchedule(taskId, timeCodeString, writer);
        } else if (scheduleType == FixType.TeachingClass.getCode()) {
            fillTeachingClassSummarySchedule(taskId, timeCodeString, writer);
        } else if (scheduleType == 5) {
            fillStudentSummarySchedule(taskId, timeCodeString, writer);
        }
        writer.setDefaultRowHeight(60);
        writer.setRowHeight(0, 30);
        writer.setRowHeight(1, 30);
        writer.setRowHeight(2, 30);

        writer.flush(new File(targetPath));

        if (null != response) {
            // 下边两行任取一行都可以
            response.addHeader("Content-Type", "application/vnd.ms-excel;charset=UTF-8");
            response.addHeader("Content-Disposition", writer.getDisposition("场地导出.xls", StandardCharsets.UTF_8));
        }
        try {
            writer.flush(response.getOutputStream(), true);
        } catch (IOException e) {
            log.error("场地导出错误" + e);
        }
        writer.close();

    }

    private void fillStudentSummarySchedule(Integer taskId, List<String> timeCodeString, ExcelWriter writer) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);

        PageInfo<AllScheduleVo> allTeacherSchedule = scheduleService.getAllStudentSchedule(taskId, taskInfo.getSchoolId(), taskInfo.getTerm(), null, null, null, null, 1, 100000);
        List<AllScheduleVo> teachingClassSchedule = allTeacherSchedule.getList();

        for (AllScheduleVo allScheduleVo : teachingClassSchedule) {
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            row.set(0, allScheduleVo.getName());
            List<ViewSchedule> schedules1 = allScheduleVo.getSchedules();
            if (CollUtil.isEmpty(schedules1)) {
                continue;
            }
            schedules1.stream().collect(Collectors.groupingBy(ViewSchedule::getTimeCode))
                    .forEach((timeCode, byTimeCodeList) -> {
                        //单节课数据
                        StringJoiner singleSchedule = new StringJoiner("\n");
                        for (ViewSchedule allScheduleDto : byTimeCodeList) {
                            //单个教学班数据 {courseName}{单双}\n{行政班名}\n{buildingName}{roomName}
                            String singleScheduleTemplate = "{} \n {} \n {} \n {} \n {}\n 班级人数:{} \n 场地容量:{} \n";
                            String courseName = allScheduleDto.getCourseName();
                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(allScheduleDto.getWeek()));
                            String teacherName = allScheduleDto.getTeacherName();
                            String roomName = allScheduleDto.getRoomName();
                            singleSchedule.add(StrUtil.format(singleScheduleTemplate,
                                    allScheduleDto.getTeachingClassName(), courseName, teacherName, roomName, weekString, allScheduleDto.getClassNum(), allScheduleDto.getRoomNum()));
                        }
                        row.set(timeCodeString.indexOf(timeCode) + 1, singleSchedule.toString());
                    });
            writer.writeRow(row);
        }


    }

    private void fillTeachingClassSummarySchedule(Integer taskId, List<String> timeCodeString, ExcelWriter writer) {


        //教学班 及对应课表
//        List<ScheduleDto> teachingClassSchedule = scheduleMapper.getScheduleByTeachingClassIds(taskId, null, null);
        List<ScheduleDto> teachingClassSchedule = new ArrayList<>();
        if (CollUtil.isEmpty(teachingClassSchedule)) {
            return;
        }
        List<Long> teachingClassIds = teachingClassSchedule.stream().map(ScheduleDto::getTeachingClassId).distinct().collect(Collectors.toList());

        //老师
        Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds).stream()
                .collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));

        //获取行政班
//        Map<Long, String> classMap = classInfoMapper.selectList(new LambdaQueryWrapper<ClassInfo>()
//                .eq(ClassInfo::getTaskId, taskId))
//                .stream().collect(Collectors.toMap(ClassInfo::getId, ClassInfo::getClassName));

        //根据教学班分组
        Map<Long, List<ScheduleDto>> scheduleTeachingClassMap = teachingClassSchedule.stream()
                .collect(Collectors.groupingBy(ScheduleDto::getTeachingClassId));
        List<Map.Entry<Long, List<ScheduleDto>>> sortKeySet = scheduleTeachingClassMap.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).collect(Collectors.toList());

        //遍历分组 生成excel
        for (Map.Entry<Long, List<ScheduleDto>> entry : sortKeySet) {
            List<ScheduleDto> scheduleList = entry.getValue();
            if (CollUtil.isEmpty(scheduleList)) {
                continue;
            }
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            //首列  设置教学班名称
            row.set(0, scheduleList.get(0).getTeachingClassName());
            scheduleList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode))
                    .forEach((timeCode, byTimeCodeList) -> {
                        //单节课数据
                        StringJoiner singleSchedule = new StringJoiner("\n");
                        for (ScheduleDto allScheduleDto : byTimeCodeList) {
                            //单个教学班数据 {courseName}{单双}\n{行政班名}\n{teacherName}
                            String singleScheduleTemplate = "{} \n {} \n {} \n {}{} \n {}";
                            String courseName = allScheduleDto.getCourseName();
                            //多个行政班情况
                            StringJoiner className = new StringJoiner(",");
                            String toClass = allScheduleDto.getToClass();
                            if (StrUtil.isNotEmpty(toClass)) {
                                for (String s : allScheduleDto.getToClass().split(",")) {
//                                    if (StrUtil.isNotBlank(classMap.get(Long.valueOf(s)))) {
//                                        className.add(classMap.get(Long.valueOf(s)));
//                                    }
                                }
                            }
                            //多教师版本
                            List<TeacherDto> teacher = teachingClassToTeacher.getOrDefault(allScheduleDto.getTeachingClassId(), new ArrayList<>());
                            teacher = teacher.stream().filter(o -> Objects.equals(allScheduleDto.getHourType(), o.getHourType())).collect(Collectors.toList());
                            String teachName = teacher.stream().map(TeacherDto::getTeacherName).collect(Collectors.joining(","));

                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(allScheduleDto.getWeek()));
                            String buildingName = allScheduleDto.getBuildingName();
                            String roomName = allScheduleDto.getRoomName();
                            singleSchedule.add(StrUtil.format(singleScheduleTemplate,
                                    courseName, className.toString(), teachName, buildingName, roomName, weekString));
                        }
                        row.set(timeCodeString.indexOf(timeCode) + 1, singleSchedule.toString());
                    });
            writer.writeRow(row);
        }


        //没课的教学班
        List<TeachingClass> teachingClassList = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId).list();
        List<Long> tcIds = teachingClassSchedule.stream()
                .map(ScheduleDto::getTeachingClassId).collect(Collectors.toList());
        teachingClassList = teachingClassList.stream().filter(o -> !tcIds.contains(o.getTeachingClassId())).collect(Collectors.toList());
        for (TeachingClass teachingClass : teachingClassList) {
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            //首列  设置行政班名称
            row.set(0, teachingClass.getTeachingClassName());
            writer.writeRow(row);
        }
    }

    private void fillRoomSummarySchedule(Integer taskId, List<String> timeCodeString, ExcelWriter writer) {


        TaskInfo taskInfo = taskInfoService.getById(taskId);

        PageInfo<AllScheduleVo> allTeacherSchedule = scheduleService.getAllRoomSchedule(taskId, taskInfo.getSchoolId(), taskInfo.getTerm(), null, null, null, 1, 100000);
        List<AllScheduleVo> teachingClassSchedule = allTeacherSchedule.getList();

        for (AllScheduleVo allScheduleVo : teachingClassSchedule) {
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            row.set(0, allScheduleVo.getName());
            List<ViewSchedule> schedules1 = allScheduleVo.getSchedules();
            if (CollUtil.isEmpty(schedules1)) {
                continue;
            }
            schedules1.stream().collect(Collectors.groupingBy(ViewSchedule::getTimeCode))
                    .forEach((timeCode, byTimeCodeList) -> {
                        //单节课数据
                        StringJoiner singleSchedule = new StringJoiner("\n");
                        for (ViewSchedule allScheduleDto : byTimeCodeList) {
                            //单个教学班数据 {courseName}{单双}\n{行政班名}\n{buildingName}{roomName}
                            String singleScheduleTemplate = "{} \n {} \n {} \n {}  \n {}\n 班级人数:{} \n 场地容量:{} \n";
                            String courseName = allScheduleDto.getCourseName();
                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(allScheduleDto.getWeek()));
                            String roomName = allScheduleDto.getRoomName();
                            String teacherName = allScheduleDto.getTeacherName();
                            singleSchedule.add(StrUtil.format(singleScheduleTemplate,
                                    allScheduleDto.getTeachingClassName(), courseName, teacherName, roomName, weekString, allScheduleDto.getClassNum(), allScheduleDto.getRoomNum()));
                        }
                        row.set(timeCodeString.indexOf(timeCode) + 1, singleSchedule.toString());
                    });
            writer.writeRow(row);
        }
    }


    @Override
    public void segmentToExcel(HttpServletResponse response, Integer taskId, String gradeId, String collegeId, String keyword) {

        List<ExcelSegment> excelSegments = new ArrayList<>();

        TaskInfo taskInfo = taskInfoService.getById(taskId);

        List<TeachingClass> teachingClasses = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId).eq(TeachingClass::getFlag, 2)
                .eq(StringUtils.isNotBlank(gradeId), TeachingClass::getGradeId, gradeId)
                .list();

        List<Course> segmentList = courseService.lambdaQuery().eq(Course::getTaskId, taskId)
                .eq(StringUtils.isNotBlank(collegeId), Course::getBaseCollegeId, collegeId)
                .like(StringUtils.isNotBlank(keyword), Course::getCourseName, keyword).eq(Course::getFlag, 2).list();

        List<Teacher> teacherList = teacherService.lambdaQuery().eq(Teacher::getTaskId, taskId).list();

        //获取总周次

        List<Teacher> aTeacher = teacherList.stream().filter(p -> p.getIdentity().equals(1)).collect(Collectors.toList());
        List<Teacher> bTeacher = teacherList.stream().filter(p -> p.getIdentity().equals(2)).collect(Collectors.toList());

        for (TeachingClass o : teachingClasses) {

            ExcelSegment excelSegment = new ExcelSegment();
            excelSegment.setTeachingClassName(o.getTeachingClassName());
            Course course = segmentList.stream().filter(p -> p.getCourseId().equals(o.getCourseId())).findFirst().orElse(null);
            if (ObjUtil.isNotNull(course)) {
                excelSegment.setSegmentName(course.getCourseName());
                excelSegment.setCollegeName(course.getCollegeName());
                excelSegment.setGradeName(o.getGradeName());
                excelSegment.setCourseType(course.getCourseType());
                List<TeachingClassStudent> list = teachingClassStudentService.lambdaQuery().eq(TeachingClassStudent::getTeachingClassId, o.getTeachingClassId()).eq(TeachingClassStudent::getFlag, 1).list();
//                excelSegment.setStudentNum(list.size());
                List<TeachingClassTeacher> teachingClassTeachers = teachingClassTeacherService.lambdaQuery().eq(TeachingClassTeacher::getTeachingClassId, o.getTeachingClassId()).list();
                List<Long> teacherIds = teachingClassTeachers.stream().map(TeachingClassTeacher::getTeacherId).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(teacherIds)) {
                    List<Teacher> teachers = aTeacher.stream().filter(p -> teacherIds.contains(p.getTeacherId())).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(teachers)) {
                        String collect = teachers.stream().map(Teacher::getTeacherName).collect(Collectors.joining(","));
                        excelSegment.setTeacher(collect);
                    }
                }


                if (CollUtil.isNotEmpty(teacherIds)) {
                    List<Teacher> teachers = bTeacher.stream().filter(p -> teacherIds.contains(p.getTeacherId())).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(teachers)) {
                        String collect = teachers.stream().map(Teacher::getTeacherName).collect(Collectors.joining(","));
                        excelSegment.setAssTeacher(collect);
                    }
                }


                List<TeachingClassWeek> teachingClassWeeks = teachingClassWeekService.lambdaQuery().eq(TeachingClassWeek::getTeachingClassId, o.getTeachingClassId()).list();
                if (CollUtil.isNotEmpty(teachingClassWeeks)) {
                    TeachingClassWeek teachingClassWeek = teachingClassWeeks.get(0);
                    int i = teachingClassWeek.getWeek().indexOf('1') + 1;
                    int j = teachingClassWeek.getWeek().lastIndexOf('1') + 1;
                    excelSegment.setWeek(i + "-" + j);
                }
                excelSegments.add(excelSegment);
            } else {
                continue;
            }
        }


        //构建标题
        String title = " {} {}环节信息导出";
        String format = StrUtil.format(title, taskInfo.getTermName(), taskInfo.getSchoolName());


        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy_MM_dd_HH_mm_ss"));

        response.setCharacterEncoding("UTF-8");
        response.setHeader("content-Type", "application/vnd.ms-excel; charset=utf-8");

        MyExcelUtils.exportExcel(excelSegments,
                format,
                "环节信息导出",
                ExcelSegment.class,
                "环节信息导出" + time + ".xls", response);


    }

    @Override
    public void lockAll(Integer taskId, String baseCollegeId) {
        RuleUsable ruleUsable = ruleUsableService.lambdaQuery()
                .eq(RuleUsable::getTaskId, taskId)
                .eq(RuleUsable::getCode, 6)
                .one();
        if (ruleUsable == null) {
            throw new BizException("管理员未设置排课规则");
        }
        String rule = ruleUsable.typeToStrong();
        List<TeachingClass> teachingClassList = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .eq(TeachingClass::getIsOptional, 0)
                .eq(StrUtil.isNotEmpty(baseCollegeId), TeachingClass::getBaseCollegeId, baseCollegeId)
                .list();
        if (StrUtil.isNotEmpty(baseCollegeId)) {
            //已根据学院过滤
            teachingClassList = teachingClassList.stream().filter(o ->
                    (rule.charAt(0) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
                            || (rule.charAt(1) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
                            || (rule.charAt(2) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
                            || (rule.charAt(3) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
            ).collect(Collectors.toList());
        }
//        else {
//            teachingClassList = teachingClassList.stream().filter(o ->
//                    (rule.charAt(0) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
//                            || (rule.charAt(1) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
//                            || (rule.charAt(2) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
//                            || (rule.charAt(3) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
//            ).collect(Collectors.toList());
//        }
        List<Long> tcIds = teachingClassList.stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());
        if (CollUtil.isNotEmpty(tcIds)) {
            teachingClassWeekService.lambdaUpdate()
                    .in(TeachingClassWeek::getTeachingClassId, tcIds)
                    .set(TeachingClassWeek::getIsLocked, 2)
                    .update();
        }

    }

    @Override
    public void lockUnLockAll(Integer taskId, Integer lock, Integer arrangeRound) {
        List<TeachingClass> teachingClassList = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .eq(arrangeRound != null, TeachingClass::getArrangeRound, arrangeRound)
                .list();


        if (CollUtil.isNotEmpty(teachingClassList)) {
            List<Long> tcIds = teachingClassList.stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());

            List<Long> newRoundIds = teachingClassList.stream()
                    .filter(o -> o.getArrangeRound() == 0)
                    .map(TeachingClass::getTeachingClassId).distinct()
                    .collect(Collectors.toList());
            int max = teachingClassList.stream().mapToInt(TeachingClass::getArrangeRound).max().getAsInt();
            tcIds.removeAll(newRoundIds);

            if (CollUtil.isNotEmpty(tcIds)) {
                Consumer<List<Long>> consumer = o -> teachingClassMapper.updateLockByTeachingClassIds(o, lock, null);
                BatchInsert.batchSplitInsert(tcIds, consumer);
//                teachingClassService.lambdaUpdate()
//                        .in(TeachingClass::getTeachingClassId, tcIds)
//                        .set(TeachingClass::getIsLocked, lock)
//                        .update();
            }

            if (CollUtil.isNotEmpty(newRoundIds)) {
                Consumer<List<Long>> consumer = o -> teachingClassMapper
                        .updateLockByTeachingClassIds(o, lock, arrangeRound == null ? max + 1 : null);
                BatchInsert.batchSplitInsert(newRoundIds, consumer);
//                teachingClassService.lambdaUpdate()
//                        .in(TeachingClass::getTeachingClassId, newRoundIds)
//                        .set(TeachingClass::getIsLocked, lock)
//                        .set(arrangeRound == null, TeachingClass::getArrangeRound, max + 1)
//                        .update();
            }

        }

    }

    @Override
    public List<TeachingClass> lockRound(Integer taskId) {
        List<TeachingClass> list = teachingClassMapper.lockRoundList(taskId);
        return list;
    }

    @Override
    public Integer isLockedNormal(Integer taskId, String collegeId) {
        String key = GlobalConstant.REDIS_SCHEDULE_LOCK_KEY + taskId;
        Integer lock = (Integer) redisUtil.hget(key, StrUtil.isEmpty(collegeId) ? "admin" : collegeId);
        if (lock == null) {
            lock = 1;
            try {
                redisUtil.hset(key, StrUtil.isEmpty(collegeId) ? "admin" : collegeId, lock);
            } catch (Exception e) {
                log.info("获取是否锁定过教学班缓存失败");
                throw new BizException("获取缓存失败");
            }
        }
        return lock;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void allNormalLocal(Integer taskId, String baseCollegeId, Integer lock) {
        RuleUsable ruleUsable = ruleUsableService.lambdaQuery()
                .eq(RuleUsable::getTaskId, taskId)
                .eq(RuleUsable::getCode, 6)
                .one();
        if (ruleUsable == null) {
            throw new BizException("管理员未设置排课规则");
        }
        String rule = ruleUsable.typeToStrong();
        List<TeachingClass> allTeachingClassList = teachingClassService.lambdaQuery()
                .eq(TeachingClass::getTaskId, taskId)
                .eq(TeachingClass::getIsEnable, 0)
                .eq(TeachingClass::getFlag, 1)
                .eq(TeachingClass::getIsOptional, 0)
                .list();
        List<TeachingClass> teachingClassList = new ArrayList<>();
        if (StrUtil.isNotEmpty(baseCollegeId)) {
            teachingClassList = allTeachingClassList.stream()
                    .filter(o -> o.getBaseCollegeId().equals(baseCollegeId) &&
                            ((rule.charAt(0) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
                                    || (rule.charAt(1) == '0' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
                                    || (rule.charAt(2) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
                                    || (rule.charAt(3) == '0' && o.getMajorProp() == 1 && o.getStudyNature() == 2))
                    ).collect(Collectors.toList());
        } else {
            teachingClassList = allTeachingClassList.stream().filter(o ->
                    (rule.charAt(0) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 1)
                            || (rule.charAt(1) == '1' && o.getMajorProp() == 2 && o.getStudyNature() == 2)
                            || (rule.charAt(2) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 1)
                            || (rule.charAt(3) == '1' && o.getMajorProp() == 1 && o.getStudyNature() == 2)
            ).collect(Collectors.toList());
        }
        List<Long> tcIds = teachingClassList.stream().map(TeachingClass::getTeachingClassId).distinct().collect(Collectors.toList());
        if (CollUtil.isNotEmpty(tcIds)) {
            teachingClassWeekService.lambdaUpdate()
                    .in(TeachingClassWeek::getTeachingClassId, tcIds)
                    .eq(TeachingClassWeek::getScheduleState, ScheduleState.NORMAL.getCode())
                    .set(TeachingClassWeek::getIsLocked, lock)
                    .update();
        }
        List<TeachingClass> subClass = teachingClassList.stream().filter(o -> StrUtil.isNotEmpty(o.getUniqueShiftSign())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(subClass)) {
            List<String> groups = subClass.stream().map(TeachingClass::getUniqueShiftSign).collect(Collectors.toList());
            subClass = allTeachingClassList.stream()
                    .filter(o -> StrUtil.isNotEmpty(o.getUniqueShiftSign())
                            && groups.contains(o.getUniqueShiftSign()))
                    .collect(Collectors.toList());
            List<Long> subIds = subClass.stream().map(TeachingClass::getTeachingClassId).collect(Collectors.toList());

            if (CollUtil.isNotEmpty(subIds)) {
                teachingClassWeekService.lambdaUpdate()
                        .in(TeachingClassWeek::getTeachingClassId, subIds)
                        .set(TeachingClassWeek::getIsLocked, lock)
                        .update();
            }
        }

        try {
            String key = GlobalConstant.REDIS_SCHEDULE_LOCK_KEY + taskId;

            //方便测试 或 手动删除redis 避免没有数据
            redisUtil.hset(key, StrUtil.isEmpty(baseCollegeId) ? "admin" : baseCollegeId, 1);

            redisUtil.hset(key, StrUtil.isEmpty(baseCollegeId) ? "admin" : baseCollegeId, lock);
        } catch (Exception e) {
            log.info("锁定解锁所有正常教学班，设置缓存失败");
            throw new BizException("设置缓存失败");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void synchronizeUpdate(Integer taskId) {
        List<Long> ids = teachingClassMapper.getAllTeachingClassId(null);
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        teachingClassWeekService.lambdaUpdate()
                .notIn(TeachingClassWeek::getTeachingClassId, ids)
                .remove();
        this.lambdaUpdate()
                .notIn(Schedule::getTeachingClassId, ids)
                .remove();
        scheduleConflictInfoService.lambdaUpdate()
                .notIn(ScheduleConflictInfo::getTeachingClassId, ids)
                .remove();
        ruleTimeProhibitService.lambdaUpdate()
                .eq(RuleTimeProhibit::getOptionType, ProhibitType.TEACHINGCLASS.getCode())
                .notIn(RuleTimeProhibit::getOptionId, ids)
                .remove();
        teachingClassTeacherService.lambdaUpdate()
                .notIn(TeachingClassTeacher::getTeachingClassId, ids)
                .remove();
        teachingClassStudentService.lambdaUpdate()
                .notIn(TeachingClassStudent::getTeachingClassId, ids)
                .remove();
    }


    private void fillTeacherSummarySchedule(Integer taskId, List<String> timeCodeString, ExcelWriter writer) {

        TaskInfo taskInfo = taskInfoService.getById(taskId);

        PageInfo<AllScheduleVo> allTeacherSchedule = scheduleService.getAllTeacherSchedule(taskId, taskInfo.getSchoolId(), null, taskInfo.getTerm(), null, 1, 100000);
        List<AllScheduleVo> teachingClassSchedule = allTeacherSchedule.getList();


        for (AllScheduleVo allScheduleVo : teachingClassSchedule) {
            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
            row.set(0, allScheduleVo.getName() + allScheduleVo.getBaseId());
            List<ViewSchedule> schedules1 = allScheduleVo.getSchedules();
            if (CollUtil.isEmpty(schedules1)) {
                continue;
            }
            schedules1.stream().collect(Collectors.groupingBy(ViewSchedule::getTimeCode))
                    .forEach((timeCode, byTimeCodeList) -> {
                        //单节课数据
                        StringJoiner singleSchedule = new StringJoiner("\n");
                        for (ViewSchedule allScheduleDto : byTimeCodeList) {
                            //单个教学班数据 {courseName}{单双}\n{行政班名}\n{buildingName}{roomName}
                            String singleScheduleTemplate = "{} \n {} \n {} \n {} \n {}\n 班级人数:{} \n 场地容量:{}";
                            String courseName = allScheduleDto.getCourseName();
                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(allScheduleDto.getWeek()));

                            String teacherName = allScheduleDto.getTeacherName();
                            String roomName = allScheduleDto.getRoomName();
                            singleSchedule.add(StrUtil.format(singleScheduleTemplate,
                                    allScheduleDto.getTeachingClassName(), courseName, teacherName, roomName, weekString, allScheduleDto.getClassNum(), allScheduleDto.getRoomNum()));
                        }
                        row.set(timeCodeString.indexOf(timeCode) + 1, singleSchedule.toString());
                    });
            writer.writeRow(row);
        }

    }


    @Override
    public void exportStudentSchedule(HttpServletResponse response, Integer taskId, Long student) {

        TaskInfo taskInfo = taskInfoService.getById(taskId);

        Student student1 = studentService.getById(student);
        String storePath = "/" + taskInfo.getSchoolName() + "/" + student1.getStudentName() + "(" + student1.getStudentId() + ")" + ".xlsx";
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;


        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);


        List<TeachingClassWeekScheduleDto> resultList = scheduleService.getStudentSchedule(taskId, student);

        int periods = basicRuleService.getMaxPeriod(taskId);
        String title = "{} 学生课表  \n  {}";
        writer.merge(taskInfo.getCycleDay(), StrUtil.format(title, student1.getStudentName(), taskInfo.getTermName()), false);
        writer.setRowHeight(0, 40);
        long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();
        long sectionNum = resultList.stream()
                .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
                .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
        String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
        String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
        writer.merge(taskInfo.getCycleDay(), filter, false);
        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}({}) \n{}\n{}\n{}{}\n{}";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String buildingName = byWeekList.get(0).getBuildingName();
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                        String format = StrUtil.format(scheduleHour, item.getCourseName(), Objects.requireNonNull(HourType.getByCode(hourType)).getMsg(),
                                item.getTeachingClassName(), teacherNames, buildingName, roomName, weekString);
                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                        if ("--".equals(s)) {
                            s = "";
                        } else {
                            s += "\n";
                        }
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                    });
                });
            });
        }

        writer.getStyleSet().setWrapText();
        writer.write(rows, false);
        setExcelForm(writer, rows, 2);

        if (null != response) {
            // 下边两行任取一行都可以
            response.addHeader("Content-Type", "application/vnd.ms-excel;charset=UTF-8");
            response.addHeader("Content-Disposition", writer.getDisposition("场地导出.xls", StandardCharsets.UTF_8));
        }
        try {
            writer.flush(response.getOutputStream(), true);
        } catch (IOException e) {
            log.error("场地导出错误" + e);
        }
        writer.close();
    }

    @Override
    public List<ArrangeTeachingClassDto> getSubTeachingClassList(List<String> subIds) {
        if (CollUtil.isEmpty(subIds)) {
            return null;
        }
        //获取课程教学班
        List<ArrangeTeachingClassDto> allTeachingClass = teachingClassMapper.getSubCourseArrangeTeachingClassDto(subIds);
        //补充教师信息
        List<Long> teachingClassIds = allTeachingClass.stream().map(ArrangeTeachingClassDto::getTeachingClassId).collect(Collectors.toList());
        Map<String, List<Teacher>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIdsArrange(teachingClassIds)
                .stream().collect(Collectors.groupingBy(teacher -> teacher.getTeachingClassId() + "-" + teacher.getHourType()));
        allTeachingClass.forEach(o -> {
            //补充教师信息 单独添加，因为教师业务以后可能会变化
            List<Teacher> teachers = teachingClassToTeacher.get(o.getTeachingClassId() + "-" + o.getHourType());
            if (CollUtil.isNotEmpty(teachers)) {
                String teacherIds = StrUtil.join(",", teachers.stream().map(Teacher::getTeacherId).collect(Collectors.toList()));
                String teacherNames = StrUtil.join(",", teachers.stream().map(Teacher::getTeacherName).collect(Collectors.toList()));
                o.setTeacherIds(teacherIds);
                o.setTeacherNames(teacherNames);
            }
        });
        return allTeachingClass;
    }

    @Override
    public List<ScheduleSelectGroup> generateTeachingClassUnitSelect(Integer taskId, GenerateTeachingClassUnitInputSelect generateTeachingClassUnit) {
        //待生成初始化课表
        List<ScheduleSelectGroup> res = new ArrayList<>();
        List<ScheduleSelect> scheduleList = scheduleSelectService.lambdaQuery()
                .eq(ScheduleSelect::getTeachingClassId, generateTeachingClassUnit.getTeachingClassId())
                .eq(ScheduleSelect::getHourType, generateTeachingClassUnit.getHourType())
                .list();

        if (CollUtil.isEmpty(scheduleList)) {
            GenerateSchedulingData generateSchedulingData = new GenerateSchedulingData();
            ArrangeTeachingClassDto teachingClassDto = new ArrangeTeachingClassDto()
                    .setTeachingClassId(-1L)
                    .setTeachingClassName(generateTeachingClassUnit.getTeachingClassName())
                    .setHourType(generateTeachingClassUnit.getHourType())
                    .setWeek(generateTeachingClassUnit.getWeek())
                    .setWeekNum(generateTeachingClassUnit.getWeekNum())
                    .setConnectNumber(generateTeachingClassUnit.getConnectNumber())
                    .setConnectSection(generateTeachingClassUnit.getConnectSection())
                    .setCourseCollegeId(generateTeachingClassUnit.getBaseCollegeId())
                    .setCourseId(generateTeachingClassUnit.getCourseId())
                    .setCourseName(generateTeachingClassUnit.getCourseName());
            LinkedList<TeachingClassUnit> teachingClassUnits = generateSchedulingData
                    .convertToTeachingClassUnit(taskId, Collections.singletonList(teachingClassDto), 0);

            teachingClassUnits.forEach(a -> {
                for (int i = 0; i < a.getConnectSection(); i++) {
                    scheduleList.add(new ScheduleSelect().setTaskId(taskId)
                            .setTeachingClassId(generateTeachingClassUnit.getTeachingClassId())
                            .setTeachingClassName(a.getTeachingClassName())
                            .setCourseId(a.getCourseId())
                            .setCourseName(a.getCourseName())
                            .setHourType(a.getTeachingType())
                            .setWeek(a.getClassWeeks())
                            .setConnectSection(a.getConnectSection())
                            .setRoomId(a.getRoomId())
                            .setTimeGroup(a.getTimeGroup())
                            .setCollegeId(a.getCollegeId()));
                }
            });
            //批量插入课表，大数据批量插入
            scheduleSelectService.saveBatch(scheduleList);
        }

        Map<String, List<ScheduleSelect>> map = scheduleList.stream().collect(Collectors.groupingBy(ScheduleSelect::getTimeGroup));
        for (Map.Entry<String, List<ScheduleSelect>> entry : map.entrySet()) {
            res.add(new ScheduleSelectGroup()
                    .setGroup(entry.getKey())
                    .setGroupList(entry.getValue()));
        }
        return res;

    }

    @Override
    public void removeTeachingClassScheduleSelect(Integer taskId, List<String> teachingClassIds) {
        scheduleSelectService.lambdaUpdate().in(ScheduleSelect::getTeachingClassId, teachingClassIds).remove();
    }


    @Override
    public void teacherBatch(HttpServletResponse response, Integer taskId, String collegeId) {

        List<Long> tId = teacherService.lambdaQuery()
                .eq(Teacher::getTaskId, taskId)
                .eq(StrUtil.isNotEmpty(collegeId), Teacher::getBaseCollegeId, collegeId)
                .isNull(StrUtil.isEmpty(collegeId), Teacher::getBaseCollegeId)
                .list().stream().map(Teacher::getTeacherId).collect(Collectors.toList());

        if (CollUtil.isNotEmpty(tId)) {
            List<Integer> taskIds = new ArrayList<>();
            taskIds.add(taskId);
            List<ViewSchedule> allSchedule = scheduleMapper.getAllSchedule(taskIds);
            List<String> teacherIds = allSchedule.stream()
                    .filter(p -> StringUtils.isNotBlank(p.getTimeCode())
                            && StringUtils.isNotBlank(p.getTeacherIds()))
                    .map(ViewSchedule::getTeacherIds).distinct().collect(Collectors.toList());

            List<String> teacherId = new ArrayList<>();

            teacherIds.forEach(o -> {
                ArrayList<String> strings = new ArrayList<>(Arrays.asList(o.split(",")));
                strings.forEach(s -> {
                    teacherId.add(s);
                });
            });

            List<String> teacherId1 = teacherId.stream().filter(p -> tId.contains(Long.valueOf(p))).collect(Collectors.toList());


            List<Long> ids = teacherId1.stream().distinct().map(Long::valueOf).collect(Collectors.toList());


            List<String> filePath = new ArrayList<>();
            ids.forEach(o -> {
                String s = scheduleService.teacherScheduleToExcel1(taskId, o, null);
                filePath.add(s);
            });


            String storePath = "教师导出" + System.currentTimeMillis() + ".zip";
            try {
                String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;
                FileUtil.del(targetPath);
                log.info("导出地址" + targetPath);
                FileOutputStream fos = new FileOutputStream(targetPath);
                ZipOutputStream zos = new ZipOutputStream(fos);

                for (String url : filePath) {
                    String[] parts = url.split("/");
                    String lastPart = parts[parts.length - 1];
                    String secondLastPart = parts[parts.length - 2];
                    String urls = GlobalConstant.OUTPUT_EXCEL_PATH + secondLastPart + File.separator + lastPart;
                    log.info(urls + "导出开始");
                    String fileName = url.substring(url.lastIndexOf("/") + 1);
                    try (InputStream is = new FileInputStream(new File(urls))) {
                        zos.putNextEntry(new ZipEntry(fileName));
                        byte[] buffer = new byte[4096];
                        int bytesRead;
                        while ((bytesRead = is.read(buffer)) != -1) {
                            zos.write(buffer, 0, bytesRead);
                        }

                        log.info(urls + "导出结束");
                        is.close();
                        zos.closeEntry();
                    } catch (IOException e) {
                        log.error("Error processing file: " + url);
                        log.error(e.toString());
                    }
                }
                zos.close();
                fos.close();


                // 设置下载响应头
                response.setContentType("application/zip");
                response.setHeader("Content-Disposition", "attachment; filename=output.zip");

                // 将 ZIP 文件写入响应流
                try (FileInputStream fis = new FileInputStream(targetPath);
                     OutputStream os = response.getOutputStream()) {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = fis.read(buffer)) != -1) {
                        os.write(buffer, 0, bytesRead);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                log.error(e.toString());
            }
        } else {
            throw new BizException("该学院不存在老师");
        }


    }


    @Override
    public void exportRoomBatch(HttpServletResponse response, Integer taskId, String buildingId) {


        List<Room> roomList = roomService.lambdaQuery().eq(Room::getTaskId, taskId).eq(Room::getBuildingId, buildingId).list();

        if (CollUtil.isNotEmpty(roomList)) {

            List<Long> roomIds = roomList.stream().map(Room::getRoomId).distinct().collect(Collectors.toList());

            List<Long> ids = scheduleService.lambdaQuery().eq(Schedule::getTaskId, taskId)
                    .in(Schedule::getRoomId, roomIds)
                    .isNotNull(Schedule::getTimeCode)
                    .list().stream().map(Schedule::getRoomId)
                    .distinct().collect(Collectors.toList());

            if (CollUtil.isNotEmpty(ids)) {

                List<String> filePath = new ArrayList<>();
                ids.forEach(o -> {
                    String s = scheduleService.exportedVenueSchedule1(taskId, o);
                    filePath.add(s);
                });


                String storePath = System.currentTimeMillis() + "场地导出.zip";

                try {
                    String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;
                    FileUtil.del(targetPath);
                    FileOutputStream fos = new FileOutputStream(targetPath);
                    ZipOutputStream zos = new ZipOutputStream(fos);

                    for (String url : filePath) {
                        String[] parts = url.split("/");
                        String lastPart = parts[parts.length - 1];
                        String secondLastPart = parts[parts.length - 2];
                        String urls = GlobalConstant.OUTPUT_EXCEL_PATH + secondLastPart + File.separator + lastPart;

                        String fileName = url.substring(url.lastIndexOf("/") + 1);
                        try (InputStream is = new FileInputStream(new File(urls))) {
                            zos.putNextEntry(new ZipEntry(fileName));

                            byte[] buffer = new byte[1024];
                            int bytesRead;
                            while ((bytesRead = is.read(buffer)) != -1) {
                                zos.write(buffer, 0, bytesRead);
                            }

                            log.info(url + "导出结束");
                            is.close();
                            zos.closeEntry();
                        } catch (IOException e) {
                            log.error("Error processing file: " + url);
                            log.error(e.toString());
                        }
                    }
                    zos.close();
                    fos.close();


                    // 设置下载响应头
                    response.setContentType("application/zip");
                    response.setHeader("Content-Disposition", "attachment; filename=output.zip");

                    // 将 ZIP 文件写入响应流
                    try (FileInputStream fis = new FileInputStream(targetPath);
                         OutputStream os = response.getOutputStream()) {
                        byte[] buffer = new byte[1024];
                        int bytesRead;
                        while ((bytesRead = fis.read(buffer)) != -1) {
                            os.write(buffer, 0, bytesRead);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                } catch (IOException e) {
                    log.error(e.toString());
                }

            } else {
                throw new BizException("该教学楼的教室没有课表");
            }


        } else {

            throw new BizException("该教学楼没有对应教室");
        }


    }


    //    @Override
    public void exportClassSchedule0(HttpServletResponse response, Integer taskId, String classId) {

        TaskInfo taskInfo = taskInfoService.getById(taskId);

        List<Student> list = studentService.lambdaQuery().eq(Student::getTaskId, taskId).eq(Student::getClassId, classId).list();

        if (CollUtil.isNotEmpty(list)) {
            Student student1 = list.get(0);
            String storePath = "/" + taskInfo.getSchoolName() + "/" + student1.getClassName() + ".xlsx";
            String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

            FileUtil.del(targetPath);
            ExcelWriter writer = ExcelUtil.getWriter(targetPath);

            List<TeachingClassWeekScheduleDto> resultList = scheduleService.getClassSchedule(taskId, classId);

            int periods = basicRuleService.getMaxPeriod(taskId);
            String title = "{} 行政班课表  \n  {}";
            writer.merge(taskInfo.getCycleDay(), StrUtil.format(title, student1.getClassName(), taskInfo.getTermName()), false);
            writer.setRowHeight(0, 40);
            long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();
            long sectionNum = resultList.stream()
                    .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
                    .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
            String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
            String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
            writer.merge(taskInfo.getCycleDay(), filter, false);
            List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
            for (TeachingClassWeekScheduleDto item : resultList) {
                //以及排好的课节
                List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
                //根据授课类型分组 使用TreeMap来排序
                TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                        .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
                mapByHourType.forEach((hourType, byHourTypeList) -> {
                    //根据timeCode分组
                    byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                        //根据week分组
                        byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                            //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                            String scheduleHour = "{}({}) \n{}\n{}\n{}{}\n{}";
                            //key 0101  节次
                            int index = Integer.parseInt(timeCode.substring(2, 4));
                            String buildingName = byWeekList.get(0).getBuildingName();
                            String roomName = byWeekList.get(0).getRoomName();
                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                            String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                            String format = StrUtil.format(scheduleHour, item.getCourseName(), Objects.requireNonNull(HourType.getByCode(hourType)).getMsg(),
                                    item.getTeachingClassName(), teacherNames, buildingName, roomName, weekString);
                            String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                            if ("--".equals(s)) {
                                s = "";
                            } else {
                                s += "\n";
                            }
                            rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                        });
                    });
                });
            }
            writer.getStyleSet().setWrapText();
            writer.write(rows, false);
            setExcelForm(writer, rows, 2);
            if (null != response) {
                // 下边两行任取一行都可以
                response.addHeader("Content-Type", "application/vnd.ms-excel;charset=UTF-8");
                response.addHeader("Content-Disposition", writer.getDisposition("行政班导出.xls", StandardCharsets.UTF_8));
            }
            try {
                writer.flush(response.getOutputStream(), true);
            } catch (IOException e) {
                log.error("行政班导出错误" + e);
            }
            writer.close();
        } else {
            throw new BizException("该行政班没有对应的学生");
        }
    }


    @Override
    public void exportClassSchedule(HttpServletResponse response, Integer taskId, String classId) {

        TaskInfo taskInfo = taskInfoService.getById(taskId);

        List<Student> list = studentService.lambdaQuery().eq(Student::getTaskId, taskId).eq(Student::getClassId, classId).list();

        if (CollUtil.isNotEmpty(list)) {
            Student student1 = list.get(0);
            String storePath = "/" + taskInfo.getSchoolName() + "/" + student1.getClassName() + ".xlsx";
            String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;

            FileUtil.del(targetPath);
            ExcelWriter writer = ExcelUtil.getWriter(targetPath);

            List<TeachingClassWeekScheduleDto> resultList = scheduleService.getClassSchedule(taskId, classId);

            int periods = basicRuleService.getMaxPeriod(taskId);
            String title = "{}班级课表";

            CellStyle header = writer.createCellStyle();
            Font headerFont = writer.createFont();
            headerFont.setFontHeightInPoints((short) 15);
            header.setFont(headerFont);
            header.setAlignment(HorizontalAlignment.CENTER);
            header.setBorderBottom(BorderStyle.THIN);
            header.setBorderLeft(BorderStyle.THIN);
            header.setBorderRight(BorderStyle.THIN);
            header.setBorderTop(BorderStyle.THIN);

            writer.merge(0, 0, 0, taskInfo.getCycleDay(), StrUtil.format(title, taskInfo.getTermName()), header);
            writer.passCurrentRow();

            writer.setRowHeight(0, 40);

            String filterTem = "班级名称: {}    所属学院：{}";
            String filter = StrUtil.format(filterTem, student1.getClassName(), student1.getCollegeName());
            writer.merge(1, 1, 0, taskInfo.getCycleDay(), filter, header);
            writer.passCurrentRow();

            List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
            for (TeachingClassWeekScheduleDto item : resultList) {
                //以及排好的课节
                List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
                //根据授课类型分组 使用TreeMap来排序
                TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                        .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
                mapByHourType.forEach((hourType, byHourTypeList) -> {
                    //根据timeCode分组
                    byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                        //根据week分组
                        byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                            //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                            String scheduleHour = "{}\n{}\n{}-{}\n{}\n";
                            //key 0101  节次
                            int index = Integer.parseInt(timeCode.substring(2, 4));
                            String buildingName = byWeekList.get(0).getBuildingName();
                            String roomName = byWeekList.get(0).getRoomName();
                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                            String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                            String format = StrUtil.format(scheduleHour,
//                                    item.getCourseName(),
                                    item.getTeachingClassName(),
                                    teacherNames, buildingName, roomName, weekString);
                            String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                            if ("--".equals(s)) {
                                s = "";
                            } else {
                                s += "\n";
                            }
                            rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                        });
                    });
                });
            }


            writer.getStyleSet().setWrapText();
            writer.write(rows, false);

            String time = "导出时间: {} ";
            writer.merge(taskInfo.getCycleDay(), StrUtil.format(time, DateUtil.now()), false);


            setExcelForm(writer, rows, 2);
            if (null != response) {
                // 下边两行任取一行都可以
                response.addHeader("Content-Type", "application/vnd.ms-excel;charset=UTF-8");
                response.addHeader("Content-Disposition", writer.getDisposition("行政班导出.xls", StandardCharsets.UTF_8));
            }
            try {
                writer.flush(response.getOutputStream(), true);
            } catch (IOException e) {
                log.error("行政班导出错误" + e);
            }
            writer.close();
        } else {
            throw new BizException("该行政班没有对应的学生");
        }
    }


    @Override
    public void exportClassScheduleV2(HttpServletResponse response, Integer taskId, Long student) {


        List<ExcelClassVo> excelClassVos = new ArrayList<>();

        List<TeachingClassWeekScheduleDto> resultList = scheduleService.getStudentSchedule(taskId, student);
        for (int i = 0; i < 5; i++) {
            ExcelClassVo excelClassVo = new ExcelClassVo();
            excelClassVo.setWeekDay(GlobalConstant.dayNameCodeMap.get("0" + (i + 1)));
            List<ExcelTimeType> excelTimeTypes = new ArrayList<>();
            for (int j = 0; j < 10; j++) {
                for (TeachingClassWeekScheduleDto item : resultList) {
                    int finalI = i;
                    String a = "";
                    if (j < 9) {
                        a = "0" + (j + 1);
                    } else {
                        a = String.valueOf((j + 1));
                    }
                    String finalA = a;
                    List<ScheduleDto> arrangeSchedule = item.getSchedules().stream()
                            .filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode()) && scheduleDto.getTimeCode().substring(0, 2).equals("0" + (finalI + 1)) && scheduleDto.getTimeCode().substring(2, 4).equals(finalA)).collect(Collectors.toList());

                    int finalJ = j;
//                    arrangeSchedule.forEach(o->{
//                        ExcelTimeType excelTimeType = new ExcelTimeType();
//                        excelTimeType.setRoom(o.getRoomName());
//                        excelTimeType.setCourseName(o.getCourseName());
//                        excelTimeType.setTeacherName(o.getTeacherName());
//                        excelTimeType.setTimeCode(String.valueOf(finalJ +1));
//                        excelTimeTypes.add(excelTimeType);
//                    });
                    excelClassVo.setExcelTimeTypes(excelTimeTypes);
                    excelClassVos.add(excelClassVo);
                }


                TaskInfo taskInfo = taskInfoService.getById(taskId);

                //构建标题
                String title = "行政班课表导出";
                String format = StrUtil.format(title, taskInfo.getTermName(), taskInfo.getSchoolName());


                String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy_MM_dd_HH_mm_ss"));

                response.setCharacterEncoding("UTF-8");
                response.setHeader("content-Type", "application/vnd.ms-excel; charset=utf-8");

                MyExcelUtils.exportExcel(excelClassVos,
                        format,
                        "行政班课表导出",
                        ExcelClassVo.class,
                        "课程禁排优先排导出" + time + ".xls", response);
            }

        }


    }


    @Override
    public void exportClassScheduleBatch(HttpServletResponse response, Integer taskId, String gradeId) {

        List<Student> studentList = studentService.lambdaQuery().eq(Student::getTaskId, taskId).in(StringUtils.isNotBlank(gradeId), Student::getGradeId, gradeId).list();

        TaskInfo taskInfo = taskInfoService.getById(taskId);

        int periods = basicRuleService.getMaxPeriod(taskId);
        if (CollUtil.isNotEmpty(studentList)) {

            Student student = studentList.get(0);

            List<String> classIds = studentList.stream().map(Student::getClassId).distinct().collect(Collectors.toList());

            if (CollUtil.isNotEmpty(classIds)) {

                List<String> filePath = new ArrayList<>();
                classIds.forEach(o -> {

                    String m = "";

                    List<Student> list = studentList.stream().filter(p -> p.getClassId().equals(o)).collect(Collectors.toList());

                    if (CollUtil.isNotEmpty(list)) {
                        Student student1 = list.get(0);

                        String fileName = student1.getClassName() + ".xlsx";
                        String storePath = taskInfo.getSchoolName() + File.separator + fileName;
                        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;


                        FileUtil.del(targetPath);
                        ExcelWriter writer = ExcelUtil.getWriter(targetPath);
                        writer.getStyleSet().setWrapText();

                        List<TeachingClassWeekScheduleDto> resultList = scheduleService.getClassSchedule(taskId, o);

                        long courseNum = resultList.stream().filter(p -> CollUtil.isNotEmpty(p.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();

                        if (courseNum == 0) {
                            m = "";
                        }


//                        String title = "{} 班级课表  \n  {}";
//                        writer.merge(taskInfo.getCycleDay(), StrUtil.format(title, student1.getClassName(), taskInfo.getTermName()), false);
//                        writer.setRowHeight(0, 40);
//                        long sectionNum = resultList.stream()
//                                .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
//                                .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
//                        String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
//                        String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
//                        writer.merge(taskInfo.getCycleDay(), filter, false);
//                        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
//                        for (TeachingClassWeekScheduleDto item : resultList) {
//                            //以及排好的课节
//                            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
//                            //根据授课类型分组 使用TreeMap来排序
//                            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
//                                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
//                            mapByHourType.forEach((hourType, byHourTypeList) -> {
//                                //根据timeCode分组
//                                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
//                                    //根据week分组
//                                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
//                                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
////                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
//                                        String scheduleHour = "{}({}) \n{}\n{}\n{}\n{} \n班级人数:{} \n场地容量:{}";
//                                        //key 0101  节次
//                                        int index = Integer.parseInt(timeCode.substring(2, 4));
//                                        String roomName = byWeekList.get(0).getRoomName();
//                                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
//                                        String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());
//
//                                        String format = StrUtil.format(scheduleHour, item.getCourseName(), Objects.requireNonNull(HourType.getByCode(hourType)).getMsg(),
//                                                item.getTeachingClassName(), teacherNames, roomName, weekString, item.getClassNum(), byWeekList.get(0).getRoomNum());
//
//                                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
//                                        if ("--".equals(s)) {
//                                            s = "";
//                                        } else {
//                                            s += "\n";
//                                        }
//                                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
//                                    });
//                                });
//                            });
//                        }
//
//                        writer.write(rows, false);
//                        setExcelForm(writer, rows, 2);

                        String title = "{}班级课表";

                        CellStyle header = writer.createCellStyle();
                        Font headerFont = writer.createFont();
                        headerFont.setFontHeightInPoints((short) 15);
                        header.setFont(headerFont);
                        header.setAlignment(HorizontalAlignment.CENTER);
                        header.setBorderBottom(BorderStyle.THIN);
                        header.setBorderLeft(BorderStyle.THIN);
                        header.setBorderRight(BorderStyle.THIN);
                        header.setBorderTop(BorderStyle.THIN);

                        writer.merge(0, 0, 0, taskInfo.getCycleDay(), StrUtil.format(title, taskInfo.getTermName()), header);
                        writer.passCurrentRow();

                        writer.setRowHeight(0, 40);

                        String filterTem = "班级名称: {}    所属学院：{}";
                        String filter = StrUtil.format(filterTem, student1.getClassName(), student1.getCollegeName());
                        writer.merge(1, 1, 0, taskInfo.getCycleDay(), filter, header);
                        writer.passCurrentRow();

                        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
                        for (TeachingClassWeekScheduleDto item : resultList) {
                            //以及排好的课节
                            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
                            //根据授课类型分组 使用TreeMap来排序
                            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
                            mapByHourType.forEach((hourType, byHourTypeList) -> {
                                //根据timeCode分组
                                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                                    //根据week分组
                                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                                        String scheduleHour = "{}\n{}\n{}-{}\n{}\n";
                                        //key 0101  节次
                                        int index = Integer.parseInt(timeCode.substring(2, 4));
                                        String buildingName = byWeekList.get(0).getBuildingName();
                                        String roomName = byWeekList.get(0).getRoomName();
                                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                                        String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                                        String format = StrUtil.format(scheduleHour,
//                                                item.getCourseName(),
                                                item.getTeachingClassName(),
                                                teacherNames, buildingName, roomName, weekString);
                                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                                        if ("--".equals(s)) {
                                            s = "";
                                        } else {
                                            s += "\n";
                                        }
                                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                                    });
                                });
                            });
                        }


                        writer.getStyleSet().setWrapText();
                        writer.write(rows, false);

                        String time = "导出时间: {} ";
                        writer.merge(taskInfo.getCycleDay(), StrUtil.format(time, DateUtil.now()), false);


                        setExcelForm(writer, rows, 2);

                        writer.close();


                        m = GlobalConstant.ACCESS_PATH + "/static/OutputExcel/" + taskInfo.getSchoolName() + "/" + fileName;

                    } else {
                        m = "";
                    }
                    if (StringUtils.isNotBlank(m)) {
                        filePath.add(m);
                    }
                });

                String storePath1 = student.getGradeName() + "行政班课表导出.zip";

                try {
                    String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath1;
                    FileUtil.del(targetPath);
                    FileOutputStream fos = new FileOutputStream(targetPath);
                    ZipOutputStream zos = new ZipOutputStream(fos);

                    for (String url : filePath) {
                        String[] parts = url.split("/");
                        String lastPart = parts[parts.length - 1];
                        String secondLastPart = parts[parts.length - 2];
                        String urls = GlobalConstant.OUTPUT_EXCEL_PATH + secondLastPart + File.separator + lastPart;

                        String fileName = url.substring(url.lastIndexOf("/") + 1);
                        try (InputStream is = new FileInputStream(new File(urls))) {
                            zos.putNextEntry(new ZipEntry(fileName));

                            byte[] buffer = new byte[1024];
                            int bytesRead;
                            while ((bytesRead = is.read(buffer)) != -1) {
                                zos.write(buffer, 0, bytesRead);
                            }

                            log.info(url + "导出结束");
                            is.close();
                            zos.closeEntry();
                        } catch (IOException e) {
                            log.error("Error processing file: " + url);
                            log.error(e.toString());
                        }
                    }
                    zos.close();
                    fos.close();

                    // 设置下载响应头
                    response.setContentType("application/zip");
                    response.setHeader("Content-Disposition", "attachment; filename=output.zip");

                    // 将 ZIP 文件写入响应流
                    try (FileInputStream fis = new FileInputStream(targetPath);
                         OutputStream os = response.getOutputStream()) {
                        byte[] buffer = new byte[1024];
                        int bytesRead;
                        while ((bytesRead = fis.read(buffer)) != -1) {
                            os.write(buffer, 0, bytesRead);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } catch (IOException e) {
                    log.error(e.toString());
                }
            }
        }
    }


    @Override
    public String exportClassSchedule1(Integer taskId, String classId) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);

        List<Student> list = studentService.lambdaQuery().eq(Student::getTaskId, taskId).eq(Student::getClassId, classId).list();

        if (CollUtil.isNotEmpty(list)) {
            Student student = list.get(0);

            String fileName = student.getClassName() + ".xlsx";
            String storePath = taskInfo.getSchoolName() + File.separator + fileName;
            String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;


            FileUtil.del(targetPath);
            ExcelWriter writer = ExcelUtil.getWriter(targetPath);
            writer.getStyleSet().setWrapText();

            List<TeachingClassWeekScheduleDto> resultList = scheduleService.getClassSchedule(taskId, classId);

            long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();

            if (courseNum == 0) {
                return "";
            }

            int periods = basicRuleService.getMaxPeriod(taskId);
            String title = "{} 教室课表  \n  {}";
            writer.merge(taskInfo.getCycleDay(), StrUtil.format(title, student.getClassName(), taskInfo.getTermName()), false);
            writer.setRowHeight(0, 40);
            long sectionNum = resultList.stream()
                    .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
                    .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
            String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
            String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
            writer.merge(taskInfo.getCycleDay(), filter, false);
            List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
            for (TeachingClassWeekScheduleDto item : resultList) {
                //以及排好的课节
                List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
                //根据授课类型分组 使用TreeMap来排序
                TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                        .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
                mapByHourType.forEach((hourType, byHourTypeList) -> {
                    //根据timeCode分组
                    byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                        //根据week分组
                        byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                            //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                            String scheduleHour = "{}({}) \n{}\n{}\n{}\n{} \n班级人数:{} \n场地容量:{}";
                            //key 0101  节次
                            int index = Integer.parseInt(timeCode.substring(2, 4));
                            String roomName = byWeekList.get(0).getRoomName();
                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                            String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                            String format = StrUtil.format(scheduleHour, item.getCourseName(), Objects.requireNonNull(HourType.getByCode(hourType)).getMsg(),
                                    item.getTeachingClassName(), teacherNames, roomName, weekString, item.getClassNum(), byWeekList.get(0).getRoomNum());

                            String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                            if ("--".equals(s)) {
                                s = "";
                            } else {
                                s += "\n";
                            }
                            rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                        });
                    });
                });
            }

            writer.write(rows, false);
            setExcelForm(writer, rows, 2);
            writer.close();


            return GlobalConstant.ACCESS_PATH + "/static/OutputExcel/" + taskInfo.getSchoolName() + "/" + fileName;

        } else {

            return "";
        }
    }

    @Override
    public boolean updateWeek(Integer taskId, List<Long> ids, String week) {
        return this.lambdaUpdate().in(Schedule::getId, ids).set(Schedule::getWeek, week).update();
    }

    @Override
    public boolean subSchedule(Integer taskId, List<Long> ids) {
        if (CollUtil.isEmpty(ids) || ids.size() <= 2) {
            throw new BizException("待排课节需大于2");
        }
        List<Schedule> scheduleList = this.lambdaQuery().in(Schedule::getId, ids).list();
        String group = UUID.randomUUID().toString();
        this.lambdaUpdate()
                .set(Schedule::getTimeGroup, group)
                .set(Schedule::getPreGroup, group)
                .in(Schedule::getId, Arrays.asList(scheduleList.get(0).getId(), scheduleList.get(1).getId()))
                .update();
        return true;
    }

    @Override
    public void exportTimeSlotRoom(Integer taskId, String schoolId, String term, HttpServletResponse response) {
        //获取排课教室数据
        List<ArrangeRoomDto> roomList = arrangeCourseDataSource.getRoomList(taskId, schoolId, term, null);
        List<ArrangePeriod> timeslotList = arrangeCourseDataSource.getTimeslotListV2(taskId, schoolId, term, null);
        //获取本学期所有计划的课表信息
        List<ArrangeScheduleDto> lockedScheduleList = arrangeCourseDataSource.getLockedScheduleList(
                taskId, null, null, null, null, null);
        lockedScheduleList.forEach(o -> {
            o.setWeek(o.getWeek().substring(0, 18));
        });
        //将获取的锁定的课表，转换成ClassHour排课课时对象
        ClassHourScheduleConvert convertor = new ClassHourScheduleConvert();
        CopyOnWriteArrayList<ClassHour> lockedClassHourList = convertor.convertToClassHourList(lockedScheduleList, timeslotList);
        //将列表，按照timeslotCode，进行分组，即作为key，生成map
        ConcurrentHashMap<String, CopyOnWriteArrayList<ClassHour>> classHourMap = ClassHourUtil.getClassHourMap(lockedClassHourList);
        //获取学期的周次信息
        //获取学期总周数，默认16周
        Long weekNum = 18L;
        LinkedList<TimeslotRoom> timeslotRoomList = new GenerateTimeslotRoom().getResult(roomList,
                timeslotList, null, classHourMap, weekNum);
//        timeslotRoomList = timeslotRoomList.stream().filter(o -> o.getRoomType() == 4000106).collect(Collectors.toCollection(LinkedList::new));
        List<ExportTimeslotRoom> exportTimeslotRooms = BeanUtil.copyToList(timeslotRoomList, ExportTimeslotRoom.class);
        exportTimeslotRooms.forEach(o -> {
            int weekSize = WeekUtil.weekSize(o.getWeeks());
            o.setWeekSize(weekSize);
            o.setClashWeeks(weekToString(o.getWeeks()));
        });

        response.setCharacterEncoding("UTF-8");
        response.setHeader("content-Type", "application/vnd.ms-excel; charset=utf-8");

        MyExcelUtils.exportExcel(exportTimeslotRooms,
                "剩余排课教室信息",
                "剩余排课教室信息",
                ExportTimeslotRoom.class,
                "剩余排课教室信息"
                        + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy_MM_dd_HH_mm_ss"))
                        + ".xls", response);

    }

    private String weekToString(String weeks) {
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < weeks.length(); i++) {
            if (weeks.charAt(i) == '1') {
                res.append(i + 1).append(",");
            }
        }
        return res.toString();
    }

    @Override
    public String exportedVenueSchedule1(Integer taskId, Long roomId) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);

        Room room = roomMapper.selectById(roomId);

        String sl = "";
        if (room.getRoomName().contains("/")) {
            sl = room.getRoomName().replace("/", "_");
        } else {
            sl = room.getRoomName();
        }

        String fileName = sl + "(" + room.getBuildingName() + ")" + ".xlsx";
        String storePath = taskInfo.getSchoolName() + File.separator + fileName;
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;


        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);
        writer.getStyleSet().setWrapText();

        List<TeachingClassWeekScheduleDto> resultList = scheduleService.getRoomSchedule(taskId, roomId, null);

        int periods = basicRuleService.getMaxPeriod(taskId);
//        String title = "{} 教室课表  \n  {}";
//        writer.merge(taskInfo.getCycleDay(), StrUtil.format(title, room.getRoomName(), taskInfo.getTermName()), false);
//        writer.setRowHeight(0, 40);
//        long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();
//        long sectionNum = resultList.stream()
//                .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
//                .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
//        String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
//        String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
//        writer.merge(taskInfo.getCycleDay(), filter, false);
//        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
//        for (TeachingClassWeekScheduleDto item : resultList) {
//            //以及排好的课节
//            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
//            //根据授课类型分组 使用TreeMap来排序
//            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
//                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
//            mapByHourType.forEach((hourType, byHourTypeList) -> {
//                //根据timeCode分组
//                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
//                    //根据week分组
//                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
//                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
////                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
//                        String scheduleHour = "{}({}) \n{}\n{}\n{}\n{} \n班级人数:{} \n场地容量:{}";
//                        //key 0101  节次
//                        int index = Integer.parseInt(timeCode.substring(2, 4));
//                        String roomName = byWeekList.get(0).getRoomName();
//                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
//                        String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());
//
//                        String format = StrUtil.format(scheduleHour, item.getCourseName(), Objects.requireNonNull(HourType.getByCode(hourType)).getMsg(),
//                                item.getTeachingClassName(), teacherNames, roomName, weekString, item.getClassNum(), byWeekList.get(0).getRoomNum());
//
//                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
//                        if ("--".equals(s)) {
//                            s = "";
//                        } else {
//                            s += "\n";
//                        }
//                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
//                    });
//                });
//            });
//        }
//
//        writer.write(rows, false);
//        setExcelForm(writer, rows, 2);

        String title = "{}教室课表";
        CellStyle header = writer.createCellStyle();
        Font headerFont = writer.createFont();
        headerFont.setFontHeightInPoints((short) 15);
        header.setFont(headerFont);
        header.setAlignment(HorizontalAlignment.CENTER);
        header.setBorderBottom(BorderStyle.THIN);
        header.setBorderLeft(BorderStyle.THIN);
        header.setBorderRight(BorderStyle.THIN);
        header.setBorderTop(BorderStyle.THIN);

        writer.merge(0, 0, 0, taskInfo.getCycleDay(), StrUtil.format(title, taskInfo.getTermName()), header);
        writer.passCurrentRow();

        writer.setRowHeight(0, 40);

        String filterTem = "场地: {}-{} 容量:{}    归属单位: {} ";
        String filter = StrUtil.format(filterTem, room.getBuildingName(), room.getRoomName(), room.getRoomNum(), room.getCollegeName() == null ? "" : room.getCollegeName());
        writer.merge(1, 1, 0, taskInfo.getCycleDay(), filter, header);
        writer.passCurrentRow();

        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}\n{}\n{}\n班级人数:{}\n";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String teacherNames = ExcelFormatUtil.getTeacherName(item.getTeachers());

                        String format = StrUtil.format(scheduleHour,
                                item.getTeachingClassName(), teacherNames, weekString, item.getClassNum());

                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                        if ("--".equals(s)) {
                            s = "";
                        } else {
                            s += "\n";
                        }
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                    });
                });
            });
        }

        writer.write(rows, false);

        String time = "导出时间: {} ";
        writer.merge(taskInfo.getCycleDay(), StrUtil.format(time, DateUtil.now()), false);


        setExcelForm(writer, rows, 2);

        writer.close();


        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel/" + taskInfo.getSchoolName() + "/" + fileName;
    }

    @Override
    public String teacherScheduleToExcel1(Integer taskId, Long teacherId, String baseCollegeName) {
        TaskInfo taskInfo = taskInfoService.getById(taskId);

        Teacher teacher = teacherService.getById(teacherId);
        String fileName = teacher.getTeacherName() + "(" + teacher.getTeacherId() + ")" + "课表.xlsx";
        String storePath = taskInfo.getSchoolName() + File.separator + fileName;
        String targetPath = GlobalConstant.OUTPUT_EXCEL_PATH + storePath;


        FileUtil.del(targetPath);
        ExcelWriter writer = ExcelUtil.getWriter(targetPath);

        writer.getStyleSet().setWrapText();

        List<TeachingClassWeekScheduleDto> resultList = scheduleService.getTeacherSchedule(taskId, teacherId, null);
        //根据最大周次生成课表模板
//        int periods = basicRuleService.getMaxPeriod(taskId);
//        String title = "{} 教师课表  \n  {}";
//        writer.merge(taskInfo.getCycleDay(), StrUtil.format(title, teacher.getTeacherName(), taskInfo.getTermName()), false);
//        writer.setRowHeight(0, 40);
//        long courseNum = resultList.stream().filter(o -> CollUtil.isNotEmpty(o.getSchedules())).map(TeachingClassWeekScheduleDto::getCourseId).distinct().count();
//        long sectionNum = resultList.stream()
//                .flatMap(studentTeachingClass -> studentTeachingClass.getSchedules().stream())
//                .filter(schedule -> ObjUtil.isNotNull(schedule.getTimeCode())).count();
//        String filterTem = "共: {}门课程，{}节课   导出时间:{} ";
//        String filter = StrUtil.format(filterTem, courseNum, sectionNum, DateUtil.now());
//        writer.merge(taskInfo.getCycleDay(), filter, false);
//        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
//        for (TeachingClassWeekScheduleDto item : resultList) {
//            //以及排好的课节
//            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
//            //根据授课类型分组 使用TreeMap来排序
//            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
//                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
//            mapByHourType.forEach((hourType, byHourTypeList) -> {
//                //根据timeCode分组
//                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
//                    //根据week分组
//                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
//                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
////                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
//                        String scheduleHour = "{}({}) \n{}\n{}{}\n{}";
//                        //key 0101  节次
//                        int index = Integer.parseInt(timeCode.substring(2, 4));
//                        String buildingName = byWeekList.get(0).getBuildingName();
//                        String roomName = byWeekList.get(0).getRoomName();
//                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
//                        String format = StrUtil.format(scheduleHour, item.getCourseName(), GlobalConstant.hourTypeMap.get(hourType)
//                                , item.getTeachingClassName(), buildingName, roomName, weekString);
//
//                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
//                        if ("--".equals(s)) {
//                            s = "";
//                        } else {
//                            s += "\n";
//                        }
//                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
//                    });
//                });
//            });
//        }
//
//        writer.write(rows, false);
//        setExcelForm(writer, rows, 2);

        //根据最大周次生成课表模板
        int periods = basicRuleService.getMaxPeriod(taskId);
        String title = "{}教师课表";

        CellStyle header = writer.createCellStyle();
        Font headerFont = writer.createFont();
        headerFont.setFontHeightInPoints((short) 15);
        header.setFont(headerFont);
        header.setAlignment(HorizontalAlignment.CENTER);
        header.setBorderBottom(BorderStyle.THIN);
        header.setBorderLeft(BorderStyle.THIN);
        header.setBorderRight(BorderStyle.THIN);
        header.setBorderTop(BorderStyle.THIN);

        writer.merge(0, 0, 0, taskInfo.getCycleDay(), StrUtil.format(title, taskInfo.getTermName()), header);
        writer.passCurrentRow();

        writer.setRowHeight(0, 40);

        String filterTem = "教师姓名: {}    教师职称: {} ";
        String filter = StrUtil.format(filterTem, teacher.getTeacherName() + "(" + teacher.getTeacherId() + ")", teacher.getProfessionalTitle());
        writer.merge(1, 1, 0, taskInfo.getCycleDay(), filter, header);
        writer.passCurrentRow();

        List<List<String>> rows = ExcelFormatUtil.getScheduleFormat(periods, taskInfo.getCycleDay());
        for (TeachingClassWeekScheduleDto item : resultList) {
            //以及排好的课节
            List<ScheduleDto> arrangeSchedule = item.getSchedules().stream().filter(scheduleDto -> StrUtil.isNotBlank(scheduleDto.getTimeCode())).collect(Collectors.toList());
            //根据授课类型分组 使用TreeMap来排序
            TreeMap<Integer, List<ScheduleDto>> mapByHourType = arrangeSchedule.stream()
                    .collect(Collectors.groupingBy(ScheduleDto::getHourType, TreeMap::new, Collectors.toList()));
            mapByHourType.forEach((hourType, byHourTypeList) -> {
                //根据timeCode分组
                byHourTypeList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode)).forEach((timeCode, byTimeCodeList) -> {
                    //根据week分组
                    byTimeCodeList.stream().collect(Collectors.groupingBy(ScheduleDto::getWeek)).forEach((week, byWeekList) -> {
                        //单个教学班 单个讲授类型 单个周次  单个节次 对应字符串
//                            String scheduleHour = "{courseName}({hourType}) \n{teachingClassName}\n{buildingName}{roomName}\n{week}"
                        String scheduleHour = "{}\n{}{}\n{}\n";
                        //key 0101  节次
                        int index = Integer.parseInt(timeCode.substring(2, 4));
                        String buildingName = byWeekList.get(0).getBuildingName();
                        String roomName = byWeekList.get(0).getRoomName();
                        String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(week));
                        String format = StrUtil.format(scheduleHour,
                                item.getTeachingClassName(), buildingName, roomName, weekString);

                        String s = rows.get(index).get(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1);
                        if ("--".equals(s)) {
                            s = "";
                        } else {
                            s += "\n";
                        }
                        rows.get(index).set(GlobalConstant.dayCode.indexOf(timeCode.substring(0, 2)) + 1, s + format);
                    });
                });
            });
        }

        writer.write(rows, false);

        String time = "导出时间: {} ";
        writer.merge(taskInfo.getCycleDay(), StrUtil.format(time, DateUtil.now()), false);

        setExcelForm(writer, rows, 2);

        writer.close();
        return GlobalConstant.ACCESS_PATH + "/static/OutputExcel/" + taskInfo.getSchoolName() + "/" + fileName;
    }

    private void fillClassSummarySchedule(Integer taskId, List<String> timeCodeString, ExcelWriter writer) {

        //教学班 及对应课表
        List<ScheduleDto> teachingClassSchedule = scheduleMapper.getAllScheduleByTeachingClassIds(taskId, null);

        List<Long> teachingClassIds = teachingClassSchedule.stream().map(ScheduleDto::getTeachingClassId).distinct().collect(Collectors.toList());
        //根据行政班对课表进行分组
        Map<String, List<ScheduleDto>> scheduleClassMap = new HashMap<>();
        for (ScheduleDto schedule : teachingClassSchedule) {
            String[] singleClass = schedule.getToClass().split(",");
            for (String single : singleClass) {
                if (StrUtil.isNotBlank(single)) {
                    scheduleClassMap.computeIfAbsent(single.trim(), k -> new ArrayList<>()).add(schedule);
                }
            }
        }
        //老师
        Map<Long, List<TeacherDto>> teachingClassToTeacher = teacherService.getTeacherByTeachingClassIds(teachingClassIds).stream()
                .collect(Collectors.groupingBy(TeacherDto::getTeachingClassId));

//        for (ClassInfo classDto : classList) {
//            List<String> row = Arrays.asList(new String[timeCodeString.size() + 1]);
//            //首列  设置行政班名称
//            row.set(0, classDto.getClassName());
//
//            List<ScheduleDto> scheduleList = scheduleClassMap.get(String.valueOf(classDto.getId()));
//            if (scheduleList == null) {
//                writer.writeRow(row);
//                continue;
//            }
//            scheduleList.stream().collect(Collectors.groupingBy(ScheduleDto::getTimeCode))
//                    .forEach((timeCode, byTimeCodeList) -> {
//                        //单节课数据
//                        StringJoiner singleSchedule = new StringJoiner("\n");
//                        for (ScheduleDto allScheduleDto : byTimeCodeList) {
//                            //单个教学班数据 {courseName}{单双}\n{teachName}\n{buildingName}{roomName}
//                            String singleScheduleTemplate = "{} \n {} \n {} \n {} {} \n {}";
//                            String teachingClassName = allScheduleDto.getTeachingClassName();
//                            String courseName = allScheduleDto.getCourseName();
//                            //多教师版本
//                            List<Teacher> teacher = teachingClassToTeacher.getOrDefault(allScheduleDto.getTeachingClassId(), new ArrayList<>());
//                            teacher = teacher.stream().filter(o -> Objects.equals(allScheduleDto.getHourType(), o.getTeacherType())).collect(Collectors.toList());
//                            String teachName = teacher.stream().map(Teacher::getTeacherName).collect(Collectors.joining(","));
//                            String weekString = StrUtil.format("[{}]周", WeekUtil.binaryToString(allScheduleDto.getWeek()));
//                            String buildingName = allScheduleDto.getBuildingName();
//                            String roomName = allScheduleDto.getRoomName();
//                            singleSchedule.add(StrUtil.format(singleScheduleTemplate,
//                                    courseName, teachingClassName, teachName, buildingName, roomName, weekString));
//                        }
//                        row.set(timeCodeString.indexOf(timeCode) + 1, singleSchedule.toString());
//                    });
//            writer.writeRow(row);
//        }

    }
}
